Render partial collection with association - ruby-on-rails

I am trying to render partials for a collection of #entries to a shared view.
In one controller, I am doing it directly to render all the #entries in the view.
<%= render(:partial => '/shared/entry', :collection => #entries) %>
On another controller, I am doing it through bookmarks. As a result, the collection is #bookmarks.entries
<%= render(:partial => '/shared/entry', :collection => #bookmarks.entries) %>
Here is my /shared/_entry.html.erb :
<div>
<%= link_to_unless_current entry.tag_list, tag_path(entry.tag_list) %>
</div>
I get the following error from the Bookmark controller, but the other controller works fine:
undefined method `tag_list' for #<Bookmark:0x007fad659b32b8>
It looks like it happens because even thought the collection is #bookmarks.entries, it is still recognizing it as a Bookmark and not as an Entry. If I change the view to the following, it works on the Bookmark, but then fails on the other controller:
<div>
<%= link_to_unless_current entry.entry.tag_list, tag_path(entry.entry.tag_list) %>
</div>
How can I make the Bookmark collection just to have entries?

What's happening here is that you've used the wrong syntax by mistake, and it just happens that there is a method with the name you've used, existing in Rails/Ruby already.
If you are expecting this
#bookmarks.entries
to return a list of Entry objects, then it won't. If #bookmarks is a collection of Bookmark objects, and a #bookmark has_many :entries, and you want to get all entries associated with all the bookmarks, you would do something like #bookmarks.collect(&:entries).flatten.uniq.
So, the syntax is wrong, and it should break, except that it just so happens that the Enumerable module, which is included in the Rails collection class, has a method called "entries", which returns an array of the items, which in this case are all Bookmark objects. So, the partial is expecting an Entry and it's getting a Bookmark, and that's what that error is telling you: you're calling tag_list on a Bookmark object.

Related

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.

Rails - custom helper repeating code with fields_for

I have created a custom helper in my application.rb file, which looks like:
module ApplicationHelper
def add_feature_field(feature_type, object_form_builder, actions_visible)
object_form_builder.object.features.build
fields = object_form_builder.fields_for :features do |features_builder|
render :partial => "features/fixed_feature", :locals => {:feature => features_builder, :fixed_feature_type => feature_type, :form_actions_visible => actions_visible}
end
end
end
I am calling this helper from my view like so:
<%= add_feature_field("First Name", customer, false) %>
<%= add_feature_field("Last Name", customer, false) %>
<%= add_feature_field("Date of Birth", customer, false) %>
This is working pretty much as anticipated, except for one major hurdle: the second time the helper is called, it renders 2 fields instead of a single field, and the third time it renders 3 fields.
I assume that what is happening is that the fields_for loop in my helper is picking up the previously built objects, and also rendering those - can anyone suggest a way of preventing this?
EDIT: For clarity, as per the comments, this helper method is being used within the Customer form; the Features being created are nested attributes.

Where to put code of "smart request" do database in rails application?

I have something like this:
in my view:
<%= render :partial => 'show', :locals => { :employee => flash[:selection][:employee] } %>
in my partial 'show':
<p>
<b>Manager:</b>
<%= Employee.find(employee.employee_id).first_name %> <%= Employee.find(employee.employee_id).last_name %>
</p>
Question:
I feel like it's not good approach to ask something from model (like: Employee.find(employee.employee_id).first_name) in the partial... And seems like in a view also... Is it right?
Where should I put such code of "smart request" to database and how then should I call it from partial?
UPD1
I did something like you advised previously...
In my controller before rendering that view (which consequently will render partial), I find this employee and put it into flash[:selection][:employee]...
This employee has much columns, like: first_name, last_name, ..., and finally employee_id. The latter employee_id is the manager of current employee (flash[:selection][:employee]).
I want to show all employee's fields in my partial. So I passed flash[:selection][:employee] like employee to the partial, then show there all stuff like: employee.first_name, ... And finally i want to show this employee.employee_id not like integer id, but actually find in database correspondent employee and put its first and last names...
Ok before rendering my view, i can set not only #employee, but also its #manager, and then pass these values to my partial...
But... this seems a bit "too much done just to show in one place this #manager's first and last names...
Am i right? or this is common usage in rails, isn't it?
I would put it in the controller that is rendering that view. Initialize an instance variable in your controller action and this will be accessible from your view and partials. Something like this:
#employee = Employee.find(...)
In recent version of Rails, passing that instance variable to a partial would be as easy as:
<%= render 'show', :employee => #employee %>
Then in your partial, you would do:
<p>
<b>Manager:</b>
<%= employee.first_name %> <%= employee.last_name %>
</p>
You are correct. You shouldn't be using finders in views. Initialize the variable that the view needs to work with in the controller.
http://guides.rubyonrails.org/action_controller_overview.html
Thanks to all, I solved the problem, providing the following association:
class Employee < ActiveRecord::Base
#...
belongs_to :manager, :class_name => "Employee", :foreign_key => "employee_id"
end
and then make the correspondent call from partial:
employee.manager.first_name

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.

Problems with passing variables to a partial

I'm using the partial "infowindow" (app/view/tech/_infowindow.html.erb) to populate a google map marker using:
new_marker = GMarker.new([t.lat, t.lng], :icon => icon, :title => t.summary, :info_window => (render_to_string :partial => "infowindow", :object => t))
but i'm getting a very odd error. When I simply put:
<%= debug(infowindow) %>
I get the full output of the hash. But when I try to reference any of the individual attributes like:
<%= infowindow.summary %>
I get thrown an undefined method `summary' for nil:NilClass even though the attribute shows up in the debug output for the entire hash. Why can I only access the entire hash and not its individual attributes in the partial?
EDIT: The top part of the returned hash:
!ruby/object:Ticket
attributes:
The model being used is a Ticket object if that helps.
What you are trying to do is call the method summary on the infowindow hash which does not exist in the Hash Class and hence the error. To access individual hash elements try this
<%= infowindow["summary"] %>

Resources