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
Related
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.
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.
undefined local variable or method `current_user' for #<ActionView::Base:0x4cdbb48>
Extracted source (around line #7):
4: <dd>
5: <%= car.name %><br />
6: <%= car.description %><br />
7: <%= link_to('edit', edit_post_path(#car)) if current_user.cars.include?(#car) %>
8: <%= link_to "Delete",
9: :controller => :car,
10: :action => :delete,
I am using session[:user_id] = #user.id to track current users login and car.id for the post id, how do I link the two together so that only the original person who posted can view the edit link?? Please help me out
personaly, to solve similar problems I've used the devise gem.
Then I make sure I have an association of some sort between the user and car tables (to use your example) and then put a simple erb check to see if they are matching. If they aren't, use the read only view otherwise allow the editable view. The erb check would look something like this.
<% if current_user.id = car.owner.id %>
...show the editable view...
<% else %>
...show the read only view...
<% end %>
If you simply don't want them to see the view if they don't "own" it, you can use a before_filter in your controller to check the user to car relationship and then do the "right thing" based upon your required application requirements. You can forward to an unauthorized action view or simply redirect them to a safe place.
Also, you can simply hide the links or buttons that would lead to the view, but no matter what I'd protect in the controller as well.
I hope this helps a bit...
EDIT: I should say that using the devise gem provides me with total 'user' support out of the box, and then you can relatively easily tailor it to your specific business requirements.
You say that you have the logged in user in #user, so you could simply do this:
<%= link_to('edit', edit_post_path(#car)) if #car.user_id == #user.id %>
I recommend using ActiveRecord's associations - they will come in handy in this and other scenarios.
app/models/user.rb
Class User < ActiveRecord::Base
has_many :posts
...
end
app/models/post.rb
Class Post < ActiveRecord::Base
belongs_to :user
...
end
Then in your view template you could do:
<%= link_to('edit', edit_post_path(#car)) if #user.posts.include?(#car) %>
For clarity, I highly recommend using the model name for variable names whenever possible e.g. #post instead of "#car" for instances of the Post model.
hey there, i'm trying to implement a drag and drop interface for a nested set in my first rails project. i'm new to rails so bear with me. my code is basically identical to this project: http://gist.github.com/128779. my problem is in the partial at this line:
<% for child in root.direct_children do %>
I'm getting a NoMethodError for direct_children which is an instance method of acts_as_nested_set, I believe. At the console if I try to create a new instance of my model, it is likewise unable to access the acts_as_nested_set instance methods, so I don't think the problem is in the partial but in the model.
Again, sorry if my terminology is wrong, I'm new to rails. Anyway, what am I doing wrong? I've got "acts_as_nested_set" in my model, just like the gist example above but my model does not appear to act as a nested set. How do I go about fixing this?
Thanks!
Here's the code for the model I am using (todo.rb):
class Todo < ActiveRecord::Base
acts_as_nested_set
end
And here's the partial:
<% content_tag :li, :id => dom_id(root) do %>
<%= content_tag :span, root.text %>
<% content_tag :ul do %>
<% for child in root.direct_children do %>
<%= render :partial => "tree", :locals => {:root => child}%>
<%end %>
<%end unless root.direct_children.empty? %>
<%end%>
root is passed to the partial from the view like:
<%= render :partial => "tree", :locals => {:root => #root} %>
and #root is defined in the controller like:
#root = Todo.find_by_parent_id(nil)
Again, the code is mostly copied wholesale with very few modifications from the gist link above.
A few things:
Have you checked that you installed the plugin properly? ./script/plugin install git://github.com/rails/acts_as_nested_set.git
Have you set up your table properly? Your model needs to have at least the following 3 columns by default (unless you want to override them): parent_id, lft, rgt. Without these acts_as_nested_set is going to have a hard time figuring out what's going on. I suggest you read the documentation at the top of this file because the readme doesn't say squat, nor does that gist for that matter.
If you've done the above, have you created a root element (not set the parent_id to anything) and then added at least one child to it?
m = Model.new
m.title = "My model's title"
m.save!
m2 = Model.new
m2.title = "My child"
m2.save!
m.add_child(m2)
I just did a quick test using the above, and afterwards I was able to do things like m.root? and m.direct_children. Good luck.
What I make from your title is that you're using quite a bit more than acts_as_nested_set. Try removing some plugins and try again.
i have a model named 'chapter' (whose only attributes are 'name' and 'course__id') which belongs to "course" (and a course has_many chapters). on the course 'Show' view, I list all chapters for that course. Easy.
I want to add a form at the end of the list so that a user can easily create a new chapter.
so in my controller, I've added this:
#newchapter=#course.chapters.build
and the form on the view looks like this:
<% form_for([#course,#newchapter]) do |c| -%>
<%= c.label :name, "New Chapter" %>: <%= c.text_field :name %>
<%= c.submit 'Create' %>
<% end %>
(for the sake of clarity: it is outside of the #course.chapters.each block)
Now, the problem is that #course.chapters.size is the actual number of chapters + the empty one i created in the controller.
Is there a way to loop through all #course.chapters except the last (empty) one? or is there a better practice (i.e. not create #newchapter or not like this)?
thanks,
Pierre
You don't want to use #course.chapters.build here because this does add an empty chapter to the course. Instead you'll want to use Chapter.new and set the :course option like this.
#newchapter = Chapter.new(:course => #course)
It may not even be necessary to specify :course here depending on how you are using #newchapter.