Passing a local variable into a nested partial - ruby-on-rails

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

Related

Rails Acts as Taggable On--Multiple Context Tag filter

I am using acts-as-taggable-on to tag a Car model. I have three different tag contexts: Make, Color & Features. The first two Make & Color are predefined in an ENV variable and the last context is user generated(automatic windows, heated seats etc.)
What I'd like to do is make it so that from my index page Cars can be filtered by multiple tags at a time. So for instance, I'd like a series of checkboxes at the top of the index page a separate set for each context where a user can check Hyundai & Red and the index of cars would populate with only red Hyundais. At the moment I have a route and some code in my Cars Controller that allows me to filter by one tag but I'd like to modify it to filter by whatever a user selects.
routes.rb
get 'tags/:tags', to: 'cars#index', as: :tag
controller
def index
if params[:keyword].present?
#cars = Car.tagged_with(params[:keyword])
else
#cars = Car.all.order(:cached_weighted_score => :desc)
end
end
The #selected_tag is tags that have been selected as parameter in index page.
Controller
def index
if params[:keyword].present?
#selected_tag = params[:keyword]
#cars = Car.tagged_with(params[:keyword])
else
#cars = Car.all.order(:cached_weighted_score => :desc)
end
end
View
It's only prototype view so you have to combine with your own code.
<% #tags.each do |tag| %>
<div>
<%= check_box_tag "keywords[]", tag.name, #selected_tag.present? ? #selected_tag.include?(tag.name) : '' %>
<%= tag.name %>
</div>
<% end %>
I hope I can give a general overview with my description.
For more information to prepopulate data in checkbox

Render a partial, but leave out a element in 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.

Rails - Using filter parameters in another controller

On my index page for one of my classes item, I have a form that filters entries in the database. You can filter by all fields that item has and all elements are represented so the code is as follows:
<%= form_tag(url_for({ :controller => :item, :action => :filter }), :id => 'filter_form') do %>
<li>
<% Category.active.each do |category| %>
<% check_box_tag "categories[]", category.id, checked?(:categories, category.id) %>
<%= category.name %>
</li>
...
<% end %>
And the controller in the filter method filters through all entries in Item using the query generated here:
#items = Item.includes(:category, ...)
.joins(:item)
.where(:category => params[:categories]
...
And so on for all fields in the filter.
I also have an export method in the same controller which exports all entries as a CSV file. The view renders what's in a helper method and passes the variable #items which is passed from the export method here as Item.active.
What I'd like is to have another method export_filter that, instead of exporting all entries in the Item table, exports just the filtered entries. In other words I'd like to get these form parameters for my filter form available in my export_filter method and use them to pass to the view and helper. How do I do this?
This is often handled by a single index method using formats (html or csv in your case). The filtering is simply another scope on the list - the rendering is handled by a block within the method, something like:
respond_to do |format|
format.html
format.csv { render text: #products.to_csv }
end
As usual - Railscasts has covered this and is a great resource:
http://railscasts.com/episodes/362-exporting-csv-and-excel?view=asciicast
To set the format - you could either do another button (and look at the value of the button) or another input that helps to select the format.

Rendering rails partial with dynamic variables

I'm trying to render a partial based on the taxon the user is inside. In my application.html.erb layout I have the following line of code:
<%= render 'spree/shared/women_subnav' if #enable_women %>
In the taxons controller, inside the show method, I have:
#taxon_id = params[:id].split('/').first
And in taxons#show I have:
<% if #taxon_id == params[:id].split('/').first %>
<%= "#enable_#{#taxon_id}" = true %>
<% end %>
When I run this I get a SyntaxError. But in taxons#show If I just enter:
<% if #taxon_id == params[:id].split('/').first %>
<%= "#enable_#{#taxon_id}" %>
<% end %>
without the '= true' then the page renders, outputting '#enable_women'. So I know it's getting the correct variable, I just need that variable to be set to true. What am I missing?
Thanks so much.
First of all I would like to give you some heads-up:
calling first on a user submittable input is not a great idea (what if I submit ?id=, it would return nil) also non utf-8 encoding will crash your app such as: ?id=Ж
Controllers are beast! I see you are setting the value of a true/false instance_variable in the view, please use controllers do define the logic before rendering its output. especially when parameter dependant.
so for a solution:
in your controller as params[:id] should suggest an INT(11) value:
def action
# returning a Taxon should be a good idea here
#taxon = Taxon.find(params[:id])
# as I would give a Taxon class an has_many relation to a User
#users = #taxon.users
end
and in your action's view
<%= render :partial => "taxons/users", collection: #users %>
of course you would have the great ability to scope the users returned and render the wanted partial accordingly.
if you want more info about "The Rails way" please read:
http://guides.rubyonrails.org/
Have fun!
use instance_variable_set
instance_variable_set "#enable_#{#taxon_id}", true
just a reminder that it's better to do these things inside a controller.

Render a rails partial based on the id of an action

I'm building a small ecommerce site that sells a variety of mens and womens clothing. i would like to render a partial based on which taxonomy the user is in. For example, if the user is at mysite.com/t/women/pants I would like to render _women.html.erb, or, if the user is at mysite.com/t/men/shirts I would like to render _men.html.erb.
I have a Taxonomy model that has_many taxons, and the Taxon model has_many products.
In taxons_controller.rb I have:
def show
#taxon = Taxon.find_by_permalink(params[:id])
return unless #taxon
#taxonomy = Spree::Taxonomy.all
#taxon_title = Spree::Taxon.all
#searcher = Spree::Config.searcher_class.new(params.merge(:taxon => #taxon.id))
#searcher.current_user = try_spree_current_user
#searcher.current_currency = current_currency
#products = #searcher.retrieve_products
respond_with(#taxon)
end
And in taxons#show I have: (which I know is wrong)
<% #taxon_title.each do |title| %>
<% #taxonomy.each do |taxonomy| %>
<% if title.name == taxonomy.name %>
<%= render "spree/shared/#{title.name.downcase}" %>
<% end %>
<% end %>
<% end %>
When I go to mysite.com/t/women/long-sleeve the rails debugger displays :
controller: spree/taxons
action: show
id: women/long-sleeve
How do I access the id of the action im inside, so that in the controller/view I can do something like:
'if id equals 'women' render "spree/shared/#{title.name.downcase}"'
where title is the name of the taxonomy?
I imagine I need to find(params[:something] in the show action of the controller, but I'm a little unclear about params.
*
*
*
#beck03076 That's a great trick. Thank you very much. But it's still not working.
In my controller I put:
#taxon_id = Spree::Taxon.find(params[:id])
Then in the action I put:
render 'spree/shared/women' if #taxon_id == params[:id]
And when I load the page it says 'the page you were looking for doesn't exist'. My partial is in the correct directory. Is my syntax correct?
My params are:
{"controller"=>"spree/taxons", "action"=>"show", "id"=>"women/long-sleeve"}
Thanks again for your help!
Whenever you are unclear about params, just put the lines below in the action and execute the action.
p "****************************"
p params
p "****************************"
Now, goto the terminal in which you started your server.
Locate those two "*******" and everything thats in between them are params.
params is basically a ruby hash.
example:
params look like this, {:controller => "hello",:action => "bye", :id => 7, :others => "OK"}
In your controller to access the id, use params[:id].(=7)
to access others, use params[:others].(="OK")

Resources