Rails render partial with collection—can't access collection - ruby-on-rails

I have a view calling this:
<%= render 'health_safety/access_requests/access_request_user', collection: #access_request_users %>
And in _access_request_user.html.erb I'm trying to use the collection, e.g.
<%= p access_request_user.inspect %>
And I get the following error:
undefined local variable or method `access_request_user' for #<#<Class:0x007fc8f0160790>:0x007fc8ebf70100>
I'm absolutely stumped, tried heaps of things but nothing's working. If it makes a difference, #access_request_users is a bunch of User objects pulled from the database.

Try defining the render as a partial, and if this alone doesn't work try defining the name of the variable:
<%= render partial: 'health_safety/access_requests/access_request_user', collection: #access_request_users, as: :access_request_user %>

Related

Rails local_assign vs. local variables

Learning from the Rails guide, I don't understand how local_assign works below:
To pass a local variable to a partial in only specific cases use the
local_assigns.
index.html.erb
<%= render user.articles %>
show.html.erb
<%= render article, full: true %>
_articles.html.erb
<h2><%= article.title %></h2>
<% if local_assigns[:full] %>
<%= simple_format article.body %>
<% else %>
<%= truncate article.body %>
<% end %>
This way it is possible to use the partial without the need to declare
all local variables.
How is the partial even being rendered by the show action when it has the name _articles, which will only show for the index action? I also don't see why you use add the option of full: true when you could have just used locals: {full:true}. What's the difference?
Regarding the use of local_assigns:
The point of this section of the guide is to show how to access optional locals in your partials. If a local variable name full may or may not be defined inside your partial, simply accessing full will cause an error when the local is not defined.
You have two options with optional locals:
First, using local_assigns[:variable_name], which will be nil when the named local wasn't provided, or the value of the variable.
Second, you can use defined?(variable_name) which will be nil when the variable is not defined, or truthy (the string "local_variable") when the local is defined.
Using defined? is simply a guard against accessing an undefined variable, you will still have to actually access the variable to get its value:
if local_assigns[:full]
if defined?(full) && full
As for your specific questions:
How is the partial even being rendered by the show action when it has the name _articles, which will only show for the index action?
This is a typo. The correct partial name is _article.html.erb. Regardless of the action, index or show, the correct partial name is the singular of the model. In the case of rendering a collection of models (as in index.html.erb), the partial should still be singularly named.
I also don't see why you use add the option of full: true when you could have just used locals: {full:true}. What's the difference?
The point is that the full: true syntax is shorter. You have two identical options:
render partial: #article, locals: { full: true }
or
render #article, full: true.
The second is significantly shorter and less redundant.

Is it possible to render a view with "get parameters"?

Is it possible to render a view with get parameters ?
For example, something like :
render "/projects/sheets?id=43"
It's because I need to render a view which uses url parameters to work properly.
I tried many ways, but it only creates parameters that I can get only in the controller and that are not available after.
It's because I want to have a view that contains the html code of many other views.
This is my current code :
allProjects.html.erb :
<% Project.where(productchief: user.id).order(:title).each do |project| %>
<%= render "/projects/sheets?id=#{project.id}" #This doesn't work. %>
<% end %>
It's because I want to have a view that contains the content of all the other views in my website to allow the users to print all this content in one time.
I don't think it's possible to do it in the way you are trying to do it. You will need to change /projects/sheets to be a partial and render that instead and pass through local variables.
So to clarify /projects/sheets.html.erb becomes /projects/_sheets.html.erb and you would then invoke as:
<%= render partial: "/projects/sheets", locals: { :project_id = project.id } %>
Then within the partial _sheets.html.erb you can make reference to project_id
Generally you should be able to access the params in a view but unless there's a very specific reason you can't, I suggested altering your routes. I may be missing some info from your original question, but let's say you have routes as:
get 'projects/sheets', to: "projects#index", as: :projects
get 'projects/sheets/:id', to: "projects#show", as: :project
That would change your urls a little but would still leave the params available. Using the routes above, for example and going to: localhost:3000/projects/sheets/5?something_fun=geeks_are_us will give the following params:
{"something_fun"=>"geeks_are_us", "controller"=>"projects", "action"=>"show", "id"=>"5"}
And if you're looking to render multiple items via a partial, you can pass the assigned variable for (in your case) 'project' to render the views but it is a partial as you appear to be rendering from a view already.
So something like:
<% #projects.each do |project| %>
<%= render partial: project, locals: {project: project} %>
<% end %>
This would try to render projects/_project.html.erb and sending project as a variable. If you need other variables in your view, just pass them in the locals hash.
Hope this is some help.

Difference between render 'posts' and render posts (without quotes)

I was going through a video and where he was rendering something like below example:
<div>
<%= render posts %> # no quotes to posts
</div>
Though he has even created a partial with _posts.html.erb, he is calling with quotes to posts.
Though he has mentioned something about it like it calls, active record model, then class and then something...i could not understand it properly. Can anyone explain clearly this with simple example.
Render with quotes
<%=render 'post'%>
Rails is going to look in the current folder for a partial file which starts with _
Render without quotes
Is still going to use the same partial, but post in this case is a variable. I think this is translating to this:
<%= render partial: "post", locals: {any_string: your_variable(in this case is post)} %>
Again I haven't checked that.
The _post.html.erb is the partial, which can look like this:
<b><%=any_string%></b>
If your_variable which was assigned to any_string will contain the string 'My name is'
Your partial will print 'My name is' in bold.
Anyway partial are more complex, and they are used for DRY-ing (Don't repeat yourself) the code.
You can see more examples here.
With quotes then you are explicitly rendering a partial of that name. Without quotes something quite interesting is happening. posts (without quotes) is a variable that will be an activemodel list of records.
Now what the call to render does is it will look at the type of each of the models and then find the correct partial for the model (which will be the name of the model camel_cased) and render each one in turn.
EDIT:
If you have a model called Post and you assign some of those records to a variable (he uses posts I assume but I'll use foo to disambiguate) like so:
foo = Post.all
then by calling render foo the render function will see that you have an activerecord collection of records, it will then check the model associated with these records (Post in our example) and will loop through all of them rendering them to a partial called _post.html.erb with a local variable for each record assigning the record to post.
<%= render foo %>
is equivalent to:
<% foo.each do |my_post| %>
<%= render partial: "post", locals: {post: my_post} %>
<% end %>

NoMethodError in Rails: Passing variables

I'm trying to pass in the variable "post" to a partial. The partial is being used on both my show#view & I'm also rendering a collection using it. Here's what it looks like (notice the "#"):
##Show#View
<%= render 'my_partial/my_view', post: #post %>
##Collection ## (I'm not using the "#" symbol)
<%= render 'my_partial/my_view', post: post %>
#Mypartial
<% if #post.something? %>
## do this
<% else %>
## do that
<% end %>
And then I get the beautiful NoMethodError undefined methodsomething?' for nil:NilClass` page when using it in my collection. I know why I'm getting it, I'm just wondering what's the DRY way(s) of getting this to work? Should I just create another partial?
Thank you
Gave my solution below.. Though, it's probably not the best way...
Why are you referencing #post in your partial? You should use post instead, that is the entire point of what you are doing (passing variables to a partial as local variables).
You must change the rendering to:
<%= render 'my_partial/my_view', locals: { post: #post } %>
Take a look in the rails guide: http://guides.rubyonrails.org/layouts_and_rendering.html
Search for "3.4.4 Passing Local Variables" and you will find more information about this whole stuff.
And for fixing your collection problem also check out the rails guide and search for: "3.4.5 Rendering Collections".

How do I pass a collection from a parent partial to an arbitrary sub-partial depth?

I'm following the RailsTutorial, and I'm currently stuck on exercise 10.5.5. Since I'm changing quite a bit, I've put the code into a paste (updated).
There are a few things to note before going into the paste:
One of the original partials receives a collection from it's "parent" partial, while the other receives the object directly from the controller.
The if statement in both of these "child" partials uses a different object name, but they're represent the same object in the database.
Ideally, I'd like to move the if statement into the grandchild, or sub-sub-, partial. I can leave it in the child partial if need be, but this doesn't feel DRY.
I've tried rendering the grandchild partial with <%= render partial: 'shared/foo', object: bar, as: :baz %> so I can use baz in the grandchild partial, since the other child partial uses baz by default. In that partial, I'm just doing <%= render partial: 'shared/foo', object: baz %>. Confused? Me, too.
You'll notice I've tried rendering the partials both with and without passing in the parent object. Maybe the parent object needs to be redefine? I also just tried <%= render partial: 'shared/micropost_delete_link', object: feed_item %>, but no luck.
Each approach I've tried so far yields the same error in the tests:
Failure/Error: before { visit root_path }
ActionView::Template::Error:
undefined method `user' for :feed_item:Symbol
This seems to indicate that I can't pass a single object received from the parent option collection: #feed_items.
Update: There was a typo in my original paste. With that fixed in the updated paste, my tests are still failing.
Failure/Error: before { visit root_path }
ActionView::Template::Error:
undefined method `user' for nil:NilClass
Somewhere along the line, I tried a different syntax, and the tests started passing:
<%= render partial: 'shared/micropost_delete_link', locals: { micropost: feed_item } %>
Even though the docs say the following should be equivalent:
<%= render :partial => "account", :object => #buyer, :as => 'user' %>
<%= render :partial => "account", :locals => { :user => #buyer } %>
Testing is still a bit unusual for me, so I can't rule out that it forced something in the suite to be re-evaluated.

Resources