Render a partial, but leave out a element in rails - ruby-on-rails

I want to render a partial but not show my button for one page. My partial looks like this;
.reward
%h4== #{number_to_currency(reward.price, precision:0)} Per Month
%h5= test.test
%h6 foo
%p= foo.description
%a.button.button-green{:href => foo(bar)} foo
And I call it like this
= render partial: 'foo', collection: bar.rewards
How can I render this partial without showing the button: This line:
%a.button.button-green{:href => foo(bar)} foo

Pass another variable with your partial-rendering.
Partial:
.reward
%h4== #{number_to_currency(reward.price, precision:0)} Per Month
%h5= artist.number_of_supporters
%h6 Supporters
%p= reward.description
- unless nopledge
%a.button.button-green{:href => new_reward_pledge_path(reward)} Pledge
Rendering it:
= render partial: 'reward', collection: artist.rewards, nopledge: true
For those of you who don't know how this works, it's fairly simple: when you render a partial in Rails (ERb, HAML, anything) you can pass along variables for the partial to use. So using render 'reward', collection: artist.rewards will give the "reward" partial access access to the artist.rewards variable, but it'll be referenced in your partial as collection. So you're able to do things like the code above does.

Related

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 %>

Rails: Render a specific partial (other than an object's default)

I want to render some child items with something other than their default partial (i.e., app/views/child_items/_child_item.html.erb). The default one was scaffolded and it isn't great for public viewing of something, but I still want to keep it for back-end management purposes.
This is what I'm going for inside the view of the parent item, assuming a partial defined in app/views/child_items/_alternate_partial.html.erb:
<%= render containing_object.child_items, :partial => 'child_items/alternate_partial' %>
But the child items still render with their default partial.
Try this one:
<%= render 'child_items/alternate_partial', :collection => containing_object.child_items %>

Passing a local variable into a nested partial

I have a page that renders a collection roughly like this:
index.html.haml
= render partial: 'cars_list', as: :this_car, collection: #cars
_cars_list.html.haml
Edit: _cars_list has other info about the individual car.
%h3 Look at these Cars!
%ul
%li Something about this car
%li car.description
%div
= render partial: 'calendars/calendar_stuff', locals: {car: this_car}
_calendar_stuff.html.haml
- if car.date == #date
%div
= car.date
_cars_contoller.rb
def index
#cars = Car.all
#date = params[:date] ? Date.parse(params[:date]) : Date.today
end
What happens in the calendar stuff partial is that this_car is always the first car in the cars collection, i.e. the same date gets printed over and over.
If I move the logic in _calendar_stuff into the cars_list partial, then the printed result changes as expected.
So it seems that Rails is not passing the local this_car object into the nested partial each time it renders the partial.
Does anyone know why?
P.S. If I structure the code with
#cars.each do |car|
render 'cars_list', locals: {this_car: car}
end
I get the same behavior.
Try this refactoring and see if you get your desired output:
index.html.haml
= render 'cars_list', collection: #cars, date: #date
Get rid of the partial keyword, and pass in the #date instance variable as a local variable to encapsulate the logic in your partials. This point I got from Rails Best Practices.
_cars_list.html.haml
%h3 Look at these Cars!
%ul
%li Something about this car
%div
= render 'calendars/calendar_stuff', car: car, date: date
As you passed in #cars as a collection, this partial will have a reference to a singularized local variable called car, which can then be passed on to the next partial, along with the now-local date variable. Since the partial being rendered is in a different location to here (over under calendars/), the partial keyword is explicitly needed here.
_calendar_stuff.html.haml
- if car.date == date
%div
= car.date
Edit
Suggested to move the call to collection to _cars_list.html.haml, but that wasn't appropriate for the problem.
Edit 2
This is the version of the above code if you still wanted to specify the local variable as this_car, so you would be overriding the car local variable that collection would have generated automatically.
index.html.haml
= render 'cars_list', collection: #cars, as: :this_car, date: #date
_cars_list.html.haml
%h3 Look at these Cars!
%ul
%li Something about this car
%li this_car.description
%div
= render 'calendars/calendar_stuff', this_car: this_car, date: date
_calendar_stuff.html.haml
- if this_car.date == date
%div
= this_car.date

How does form template work in Rails

If we create the default scaffold in Rails, both the edit.html.erb and new.html.erb render the same _form.html.erb within. Both create forms with certain similarities and differences.
Such as:
Both create <form method="post" ...>
The submit buttons have different texts <input value='Create model'
.. and <input value='New model' ..
My questions:
How does the conditional rendering work?
How to display form elements conditionally? E.g., show this
<input> only if it is called via edit.html.erb, but do not show
it if called via new.html.erb.
If the method in q.2 possible, is it the right way? We are reusing
code instead of replicating the form all over again, isn't it?
Assuming you're following RESTful conventions, the differences you see between edit and new are based on the state of the object that you pass to the form. Rails can tell the difference between a new object and one that has been persisted by using the #new_record? method.
Model.new.new_record? # => true
Model.first.new_record? # => false
In your #new controller action, you probably have something like:
#model = Model.new
In your #edit action, you probably have something like:
#model = Mode.find(params[:id])
This #model object is then passed to the form, which handles the conditional logic internally. Another difference in the form you should notice is that the #edit version has a hidden input field that tells the server to use the PUT HTTP method.
Update
It looks like Rails actually uses the persisted? method internally as opposed to new_record?. The difference is that persisted? checks whether the record has been deleted. Otherwise, they are identical (but opposite)
You can do as it:
In new.html.erb:
<%= render :partial =>'form', :locals => {:action => 'new', :f => f } %>
In edit.html.erb:
<%= render :partial =>'form', :locals => {:action => 'edit', :f => f } %>
In _form.html.erb:
if action == 'new'
or
if action == 'edit'
Also you can send other parameters by :locals such as :show_mobile => false.

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