I have a partial that needs to have some controller logic run before it can render without issue. Is there some way to associate the partial with some controller logic that is run whenever it is rendered?
For example, this is what my current code looks like:
MyDataController:
class MyDataController < ApplicationController
def view
@obj = MyData.find(params[:id])
run_logic_for_partial
end
def some_method_i_dont_know_about
@obj = MyData.find(params[:id])
# Doesn't call run_logic_for_partial
end
def run_logic_for_partial
@important_hash = {}
for item in @obj.internal_array
@important_hash[item] = "Important value"
end
end
end
view.html.erb:
Name: <%= @obj.name %>
Date: <%= @obj.date %>
<%= render :partial => "my_partial" %>
some_method_i_dont_know_about.html.erb:
Name: <%= @obj.name %>
User: <%= @obj.user %>
<%# This will fail because @important_hash isn't initialized %>
<%= render :partial => "my_partial" %>
_my_partial.html.erb:
<% for item in @obj.internal_array %>
<%= item.to_s %>: <%= @important_hash[item] %>
<% end %>
How can I make sure that run_logic_for_partial
is called whenever _my_partial.html.erb
is rendered, even if the method isn't explicitly called from the controller? If I can't, are there any common patterns used in Rails to deal with these kinds of situations?
You should be using a views helper for this sort of logic. If you generated your resource using rails generate
, a helper file for your resource should already be in your app/helpers
directory. Otherwise, you can create it yourself:
# app/helpers/my_data.rb
module MyDataHelper
def run_logic_for_partial(obj)
important_hash = {}
for item in obj.internal_array
important_hash[item] = "Important value" // you'll need to modify this keying to suit your purposes
end
important_hash
end
end
Then, in your partial, pass the object you want to operate on to your helper:
# _my_partial.html.erb
<% important_hash = run_logic_for_partial(@obj) %>
<% for item in important_hash %>
<%= item.to_s %>: <%= important_hash[item] %>
<% end %>
Or:
# app/helpers/my_data.rb
module MyDataHelper
def run_logic_for_partial(item)
# Do your logic
"Important value"
end
end
# _my_partial.html.erb
<% for item in @obj.internal_array %>
<%= item.to_s %>: <%= run_logic_for_partial(item) %>
<% end %>
EDIT:
As commented Ian Kennedy points out, this logic can also reasonably be abstracted into a convenience method in your model:
# app/models/obj.rb
def important_hash
hash = {}
for item in internal_array
important_hash[item] = "Important value"
end
hash
end
Then, you'd access the important_hash
attribute in the following manner in your partial:
# _my_partial.html.erb
<% for item in @obj.important_hash %>
<%= item.to_s %>: <%= item %>
<% end %>
What you're trying to do runs against the grain of how Rails controllers/views are designed to be used. It would be better to structure things a bit differently. Why not put run_logic_for_partial
into a helper, and make it take an argument (rather than implicitly working on @obj
)?
To see an example of a view "helper", look here: http://guides.rubyonrails.org/getting_started.html#view-helpers