Questions about Rails render call - ruby-on-rails

When seeing in the code the following lines :
<%= render :partial => 'ingredients/form',
:locals => {:form => recipe_form} %>
I wonder what is actually happening.
I have noticed render is a part of RenderingHelper. How do I know which object I can use while writing? How can I use it without RenderingHelper prefix as in Java (i.e. RenderingHelper.render). Am I inheriting from it in the form view?
Since I know Java and C#, I have searched for ingredients/form and couldn't find it in the code. I am guessing it is part of the convention over configuration rule. What is it? Where is it defined?
Regarding the :locals => {:form => recipe_form} line, is that a parameter sent to render? Is that double assignment? What does the => operator actually do here?
If it is a parameter it was hard to understand from the render signature:
Returns the result of a render that's dictated by the options hash. The primary options are:
:partial - See ActionView::PartialRenderer.
:file - Renders an explicit template file (this used to be the old default), add :locals to pass in those.
:inline - Renders an inline template similar to how it's done in the controller.
:text - Renders the text passed in out.

In the future, please try to ask one question per post.
RenderingHelper is a module, and its methods are made available via an include somewhere. Read more about how Ruby's modules work.
Partial filenames are always prfixied with an underscore, your partial will be located in app/views/ingredients/_form.html.erb
Both :form and :locals are keys in an options hash being passed to render; The corrpsponding value for :locals is a nested hash, which contains one key, :form whose value is a local variable named recipe_form. This might be more obvious if you explicitly specify some of the optional punctuation:
<%= render({:partial => 'ingredients/form', :locals => {:form => recipe_form}}) %>
Ruby (and Rails specifically) use variable length lists of arguments in the form of key/value hashes. They aren't hard to use or understand at all once you understand the basic syntax

2. "ingredients/form" isn't code--it's a string. It refers to the _form partial for the ingredient model. It's located in app/views/ingredients/_form.erb.html.
3. :locals => { ... } means the render function is getting a map entry with the symbol :locals as its key. render knows what to do with that map.
It's not "double assignment", it's that the value of the :locals key is also a map. =>, or the "hash rocket", is Ruby 1.8/1.9 syntax for assigning a map value to a map key. In Ruby 1.9 you can use a shortcut, locals: { ... }.
(IMO which is more readable depends on the values--when the values are keys, I think the new syntax is heinous, otherwise I like it.)
4. How is the signature difficult to understand? The argument is a hash of options.

Related

how can I find if a global variable or route for my views is defined in rails?

I am working with a project already started by other person, I found this part of code and I seriously dont know what means.
I understand :partial -> "tests/show_#{test.type}" sends to a view... in my db type is a number, so, I guess in some part it might decided depending of the number which view to get, and I am not sure if that is on :locals, in case is that, I dont know where to look for, anybody knows what does :locals mean? (i thought was a router, but it is not) and, the view it shows its a show_questions and the others are show_types and so on...(never show_1, show_2 ...) , but like i said, type brings a number.
= render :partial => "tests/show_#{test.type}", :locals => {:test=> test, :index => idx}
Any idea how to debug this to find out how it converts into name of the view?? I dont know where to look for
:locals are the local variables that you pass into the partial.
In your example, the variables 'test' and 'index' will be accessible from the "tests/show_#{test.type}" partial.

Dynamic rendering of partials in Rails 3

In the app I'm working on, I have defined a method task_types in the model:
task.rb
def self.task_types
["ad_hoc"]
end
I use task_types to populate a drop-down menu, but I would also like to use it to dynamically render a partial.
What I have in mind is, for each task type, there will be an associated comment box. I went ahead and made a helper that will call the correct partial depending upon which task type was selected:
#tasks_helper.rb
module TasksHelper
def completion_comment(task)
task_types = #task.task_type
render :partial => "#{Task.task_types}", :locals => {:task => task}
end
end
Unfortunately, when I called completion_comment, I received the error message "The partial name (["ad_hoc"]) is not a valid Ruby identifier."
What I'm looking for is a dynamic way to render the appropriate partial. I think I'm on the right track, but I'm not sure how to extract the array elements from my task_types method (as you can see in the error message, the brackets and quotation marks are getting pulled into the render action). Or, perhaps I need to utilize a different method for dynamically rendering the partial. Any help is appreciated.
Here's what worked:
module TasksHelper
def render_task_form(task)
render :partial => "/tasks/completed/#{task.task_type.downcase}"
end
end
I had tried this solution much earlier, and had received an error that "The partial name (/tasks/completed/) is not a valid Ruby identifier; make sure your partial name starts with a letter or underscore, and is followed by any combinations of letters, numbers, or underscores."
I tried it again, and to remedy this problem I deleted all tasks from the database. Now the partial renders dynamically. Hopefully this helps someone else!
You need a string instead of the entire task_types array. #task.task_type should return a key that a) matches an element in the task types array and b) matches a known partial.
The following is a bit more complicated that it needs to be but should do the trick:
tasks_helper.rb
module TasksHelper
def completion_comment(task)
if Task.task_types.include? task.task_type
render :partial => task.task_type,
:locals => {
:task => task
}
else
# render a generic comment box here
end
end
end
In Rails 4, the view or the partial name is supposed to respond to a valid Ruby identifier.
So, the entire view name must follow the same format as a ruby-identifier:
it should start with a _ or character
it cannot start with a number
it can have only _ and alphanumerics.
So, considering that task_type is a valid ruby identifier (which it should be), it will work. In generate this code will not work in Rails 4
render '/tasks/completed/some-task'
but this will work
render '/tasks/completed/some_task' # note the underscore.

Including a partial "as is" in Ruby on Rails

I am using stache for server-side evaluation of Mustache templates. I would like to re-use some of these templates on the client-side from JavaScript using ICanHaz.js, but to do so I need to include them into script tags. I would like to avoid duplicating the templates (DRY), but obviously, the templates must not be evaluated before being sent to the client, so using a simple render :partial invocation like in this (HAML) snippet does not work:
%script{:id => 'project_snippet'}
= render :partial => 'project'
Is there any way to include a partial without evaluating it using the underlying template engine (kind of like a raw include)?
In other places the partial is to be used as regular partial, i.e., evaluation is supposed to happen, so changing the file extension to always avoid evaluation is not an option.
do you need a partial as is or you want it to be rendered as HTML with some placeholders for JavaScript templating? you can pass :locals => { ... } with something to be replaced by JS template engine later i.e.
%script{:id => 'project_snippet'}
= render :partial => 'project', :locals => {:name => '{{{ project_name }}}'}
if as is then read the partial content (but it doesn't look like you want this)
%script{:id => 'project_snippet'}
= File.open("#{path/to}/partial.html.haml", "r").read
Well, it seems that I should have read the stache documentation: There is a tag helper available, so
= template_include_tag 'projects/project'
will do the trick after setting the template base directory in an initializer:
Stache.configure do |c|
c.template_base_path = "#{Rails.root}/app/views"
end

Rendering a Heterogeneous Collection: How can I specify a single directory for the partials?

I have a collection, #comments, that is heterogeneous but hierarchical. Each comment is either an instance of Comment or some derived class, like ActionComment or InactionComment. I am rendering a different partial for each type of Comment. The View code is:
= render #comments
As all the partials are related, I would like to keep them in a single view directory, i.e.:
app/views/comments/_comment.haml
app/views/comments/_action_comment.haml
app/views/comments/_inaction_comment.haml
But right now in order to use the automatic rendering of the correct partial, I am using separate directories, like:
app/views/comments/_comment.haml
app/views/action_comments/_action_comment.haml
app/views/inaction_comments/_inaction_comment.haml
Rails 3.2 makes a Model#to_partial_path method available which allows you (as its name suggests) to override the partial pathname.
def to_partial_path
self.action.to_s
end
The path it returns does not include the leading underscore and is assumed to be relative to .../views/modelname/. See http://blog.plataformatec.com.br/2012/01/my-five-favorite-hidden-features-in-rails-3-2/ for an overview
You can't do it quite as magically, but you can do it by just rendering each item individually and specifying the partial.
example in haml:
- #comments.each do |c|
= render :partial => "comments/#{c.class.to_s.underscore}", :locals => {:comment => c}

How can i use attribute_fu and treat the first element differently?

I am using attribute_fu with rails 2.2 and I would like to treat the first nested element differently than the rest, meaning I would like to render a different partial or pass a parameter to the existing partial.
Is that possible ?
Thanks,
Cezar
I found the answer to my own question !
For those running into the same problem: you can pass a locals hash like you would pass it to a normal render :partial like so :
<%= f.render_associated_form(#your_model, :locals => {:var => value}) %>
Regards,
Cezar

Resources