Reputation: 9895
I have a few controller methods that are extremely similar and I was wondering what the best way to refactor them would be. First thing that comes to mind would be somehow passing in two blocks to a helper method, but I'm not sure how to do that either.
def action_a
if @last_updated.nil?
@variable_a = @stuff_a
else
@variable_a = (@stuff_a.select{ |item| item.updated_at > @last_updated }
end
end
def action_b
if @last_updated.nil?
@variable_b = @stuff_b.some_method
else
@variable_b = @stuff_b.some_method.select{ |stuff| item.updated_at > @last_updated }
end
end
It just seems like I'm constantly checking if @last_updated
is nil (I set the @last_updated
instance variable in a before_filter
. If I could somehow pass the stuff inside the if
as a block and the stuff in the else
as another block, then I could remove the if @last_updated.nil?
duplication?
What is the best way of accomplishing this for many methods?
Update
Where I specify @stuff_a
and @stuff_b
, they are always returning an array (since I use .select
).
Upvotes: 0
Views: 230
Reputation: 168101
You need to extract your condition in a separate def
block and use it later on:
def select_updates a
@last_updated.nil? ? a : a.select{ |item| item.updated_at > @last_updated }
end
def action_a; @variable_a = select_updates(@stuff_a) end
def action_b; @variable_b = select_updates(@stuff_b.some_method) end
Upvotes: 1
Reputation: 16629
AS I can see, you could do the followings
have two scope for each
Ex:
class Stuff < ActiveRecord::Base
scope :updated_at, lambda {|updated_date|
{:conditions => "updated_at > #{updated_date}"}
}
end
class Item < ActiveRecord::Base
scope :updated_at, lambda {|updated_date|
{:conditions => "updated_at > #{updated_date}"}
}
end
in your controller do this
def action_a
@variable_a = update_method(@stuff_a)
end
def action_b
@variable_b = update_method(@stuff_b)
end
private
def update_method(obj)
result = nil
if @last_updated.nil?
result = obj.some_method
else
result = obj.some_method.updated_at(@last_updated)
end
result
end
HTH
Upvotes: 0
Reputation: 230336
Take a look at this. It's DRYer and should yield identical results.
def action_a
do_the_processing :"@variable_a", @stuff_a
end
def action_b
do_the_processing :"@variable_b", @stuff_b.some_method
end
private
def do_the_processing var_name, collection
if @last_updated.nil?
instance_variable_set var_name, collection
else
instance_variable_set var_name, collection.select{ |item| item.updated_at > @last_updated }
end
end
And here's the two blocks approach (just for fun) (uses 1.9's stabby lambda syntax)
def action_a
check_last_updated is_nil: -> { @variable_a = @stuff_a },
is_not_nil: -> { @variable_a = (@stuff_a.select{ |item| item.updated_at > @last_updated } }
end
def action_b
check_last_updated is_nil: -> { @variable_b = @stuff_b.some_method },
is_not_nil: -> { @variable_b = @stuff_b.some_method.select{ |stuff| item.updated_at > @last_updated } }
end
private
def check_last_updated blocks = {}
if @last_updated.nil?
blocks[:is_nil].try(:call)
else
blocks[:is_not_nil].try(:call)
end
end
Upvotes: 3