Reputation: 8331
I have a Like model, it connects users liking items. Additonally to the standard liked
status, items can be spinned
& pinned
, all being boolean fields.
Like Model
_________________________________________________
| item_id | user_id | liked | spinned | pinned |
|---------|---------|---------|----------|--------|
| 1 | 1 | true | true | false |
| 2 | 1 | false | true | true |
| 3 | 2 | true | false | false |
-------------------------------------------------
The different states of an item all get updated via the same AJAX
call, calling the same action
in my likes controller
. When the like does not yet exist, it creates a like with the desired state being true.
likes_controller
def index
# get the item id
action = params[:act]
mid = params[:mid]
# gets the desired like item to see if it already exists
like = Like.where(:item_id => mid, :user_id => current_user.id).first
case action
# like the item
when "like"
# if the item doesn't exist
if like.blank?
# create the like
Like.create(:user_id => current_user.id, :item_id => mid, :liked => true)
else
# else toggle the liked status
like.toggle! :liked
end
# pin the item
when "pin"
if like.blank?
# create the like
Like.create(:user_id => current_user.id, :item_id => mid, :pinned => true)
else
# else toggle the pinned status
like.toggle! :pinned
end
# spin the item
when "spin"
if like.blank?
# create the like
Like.create(:user_id => current_user.id, :item_id => mid, :spinned => true)
else
# else toggle the spinned status
like.toggle! :spinned
end
end
end
As you see, the code in the case
gets very repetitive, I wanted to know if I could use my action
('like', 'pin', 'spin') variable more effectively.
I could easily convert the action
to the appropriate field name ("like" => "liked", "pin" => "pinned", "spin" => "spinned") by sending another parameter value from my view
.
Could I then use this to only have one block of code instead of 3 similar ones?
iE
action = "liked" # this would change depending on the desired action
# if the item doesn't exist
if like.blank?
# original
Like.create(:user_id => current_user.id, :item_id => mid, :liked => true)
# doesn't work, how would I do this appropriately?
Like.create("user_id = ?, item_id = ?, ? = true", current_user.id, mid, action)
else
# this works!, what about SQL injection? How can I prevent this?
like.toggle!("#{action}")
end
Upvotes: 0
Views: 700
Reputation: 1493
You can use select or new and then save if the atomicity of events is not a major issue.
like = Like.where(:item_id => mid, :user_id => current_user.id).first
like ||= Like.new(:item_id => mid, :user_id => current_user.id, :pinned => false, :spinned => false, :liked => false)
when "like"
like.liked = !like.liked
when "spin"
like.spinned = !like.spinned
when "pin"
like.pinned = !like.pinned
end
like.save!
Upvotes: 1
Reputation: 8331
As it turns out I could simply use my variable action
instead of the column selector :column
when using create()
and toggle()
.
The result being:
if like.blank?
# create the like
Like.create(:user_id => current_user, :item_id => mid, action => true)
else
# else toggle the desired status
like.toggle!(action)
end
Upvotes: 0