I have a very standard CRUD app in Rails & Jquery Mobile with two models relevant to my question:
class Wall < ActiveRecord::Base
has_many :problems
end
class Problem < ActiveRecord::Base
# boolean attribute is_live
belongs_to :wall
end
When showing each Wall, I’m grabbing each Problem belonging to that wall for which is_live == true. My goal now is to create a method for ‘clearing’ a wall of all problems by finding each problem on a wall with is_live == true and updating is_live to be false.
I do not, however, know the best practice/approach to find and update each of the appropriate objects. (This will be a restricted function only available to those with ‘admin’ privileges.) Should I:
-
Add a link_to that posts to a newly created WallController action
like below?def clear_wall @wall = Wall.find(params[:id]) @problems = @wall.problems.where(:is_live => true) @problem.each {|p| p.update_attribute(:is_live => false) } redirect_to(walls_url) end -
Add a form_for that submits to execute the same controller code?
-
Add a new method to the Wall model to handle this?
I’m probably overthinking this pretty heavily, but I’d appreciate some direction before I stumble down an overly-complicated road that causes problems in the future.
As you don’t need to pass any data to the server other than the ID which will be in the URL, so using a
link_toshould be fine.Make this method POST using
:method => :postas you are changing data on the server – changing data without POSTing is a bad ideaIf you don’t need a special view, you can also use
:remote => trueto use AJAX to submit a form to this URL. Otherwise, theredirect_toin your question will suffice.See the ActionView docs for more info about how to construct your
link_toI would then Implement the logic (as below) in your controller directly
Using
update_allto update many objects in the DBActiveRecord has an
update_allmethod you can call on anActiveRecord::RelationIt doesn’t load the models from the DB, or call callbacks but since setting anything that is not false to false is functionally equivalent to setting everything to false using it like this might suit your purpose.
Wall.find(params[:id]).problems.update_all(:is_live => false)You can supply a conditional parameter to
update_allWall.find(params[:id]).problems.update_all(:is_live => false, "is_live = true")or alternatively perform a where first, but this will load all of the data from the DB first and in your case seems unnecessary. The important thing to note here, is that the
update_allmethod works onActiveRecord::Relationand notActiveRecord::BaseWall.find(params[:id]).problems.where(:is_live => true).update_all(:is_live => false)