I recently decided I wanted to list all the users in my Ruby On Rails application - since I couldn't figure out how to list them any other way, I decided to use partials.
I have the following on my administration page (just hooked up to a its own administration controller):
<%= render :partial => User.find(:all) %>
I then have a file called _user.html.erb in my users view folder. This contains the following:
<ul>
<% div_for #user.object_id do %>
<li><%= link_to user.username, user.username %></li>
<% end %>
</ul>
When the application runs and I go to the administration page, I get the following error:
undefined method `id' for 4:Fixnum
It says it's because of this line (which is in the partial file):
<% div_for #user.object_id do %>
I'm unsure why this happens (and have googled for hours to try and find results and only find solutions that don't work for me). I think it's something to do with my usage of the #user instance variable, but I'm not totally sure.
You get that error because div_for expects an active record object as an argument, which it calls the id method on. You pass in a fixnum (the result of #user.object_id), which is not an active record object and does not have an id method.
So pass in #user instead of #user.object_id and it will work.
Also you should use user instead of #user, rails 3 does not set instance variables for partials anymore.
Lose the .object_id part. I seriously can't think why are you using object_id!Do you have a good reason for doing so? Anyway div_for wraps a div around an object, so leave the .object_id part!
instead of object you are using it's column or visa varsa you are using at that time you will get this kind of error.
Example
I am using id instead of user = User.first object.
Try this, it worked for me.
#item.unit_of_measure.name
instead of
#item.unit_of_measure_id.name
Related
I'm currently going through Michael Hartl's railstutorial.org, and have run into a question that Google/Stackoverflow don't seem to be answering: The tutorial has us display user information in the view by putting <%= #user.name %>, <%= #user.email %> in show.html.erb. In the controller, it has us define a show method: #user = User.find(params[:id]).
I understand why this works, but what I don't understand is why the following code does not produce the same result (I removed the show method from the controller and tried to place all the code in the view). These are my editions to show.html.erb:
<%= #user.find(params[:id]).name %>, <%= #user.find(params[:id]).email %>
It returns "undefined method `find' for nil:NilClass".
I'm sure you understand by now from the other answers and probably the tutorial that you should not have this logic in the view, HOWEVER, to answer your question:
The reason why <%= #user.find(params[:id]).name %> generates the error
undefined method 'find' for nil:NilClass is because #user is an instance variable which you deleted from the show method in the controller. So now, #user is nil and doesn't exist. Also, when you want to query the database you must use the class (model) name which is User instead of #user.
So whiles its bad practice to do this, if you wanted to, you could do <%= User.find(params[:id]).name %> (as long as its a correct id) and that would work. Your params are available in the view as they are in the controller too.
Finally, if you intend to use the show view, you cannot completely delete the show method, you must have at least:
def show
end
in order for it to work.
params is probably not available in the view, and it shouldn't.
Your problem is the main reason why you should do your data preparation in the controller: to catch issues with the data. That's the reason a controller exists.
Your code would make two requests to the database instead of one, if it wouldn't be for rails side query caching.
Prepare your #user in the controller and access it in the view. It will make testing and refactoring your code way easier and greatly improve readability.
Compare
<%= User.find(params[:id]).name %>, <%= User.find(params[:id]).email %>
VS.
<%= #user.name %>, <%= #user.email %>
You really shouldn't have a lot of logic in the views, but I think the code you are looking for is:
<%= User.find(params[:id]).name %>, <%= User.find(params[:id]).email %>
I've been stuck on this problem for days. First off, I now know this code is horribly wrong. I've been trying to fix it, but it's way more important in the short term that this link is created. In my view (I'm so sorry), I call the create method like this, if a certain condition is met:
index.html.erb (controller: subjects_controller)
<%= Baseline.create(subject_id: sub.subject_id) %>
I do this several times on the page, from several controllers (i.e., FollowUp3Week.create(subject_id: sub.subject_id) works). All of the other controllers work. I've checked, and double checked, every controller action and compared them to each other, and they appear the same.
So instead of creating the record, it leaves something like this instead:
#<Baseline:0x007f944c4f7f80>
I'm at a bit of a trouble shooting loss. Once again, I know how wrong it is to have these database actions in the view. But I didn't know that when I made the page, and I really need this to function before I can take the time to learn how to rearrange everything through the MVC.
Any advice would be greatly appreciated. Let me know what other code you might want to look at.
EDIT 1.
link Creation:
<% if Baseline.where(subject_id: sub.subject_id).first != nil %>
<%= link_to "edit", baseline_path(Baseline.where(subject_id: sub.subject_id).first) %>
<% else %>
<%= Baseline.create(subject_id: sub.subject_id) %>
<% end %>
First of all, making DB calls in views is a big NO! NO!
Secondly, to answer why you see the output as
#<Baseline:0x007f944c4f7f80>
for
<%= Baseline.create(subject_id: sub.subject_id) %>
You are trying to render an instance of Baseline model. Its just how the instance would be displayed. If you want to display a particular attribute's value in view then just do
<%= Baseline.create(subject_id: sub.subject_id).subject_id %>
Also, this code will not create a link. To create a link you would have to call link_to helper in your view.
What you need to do is, move the Baseline.create call in the controller. Set an instance variable in the action which renders this particular view as below:
def action_name
#baseline = Baseline.create(subject_id: sub.subject_id)
end
After this in you view you can easily access all the attributes of #baseline instance.
For example:
To access subject_id
<%= #baseline.subject_id %>
To create a link for show page of #baseline, provided you have a RESTful route to show action for baselines
<%= link_to "Some Link", #baseline %>
I am experiencing a very odd problem; I get this error
undefined method `to_datetime' for nil:NilClass"
when render 'modal' is before render 'post' in show.html.erb, but not if it is after:
<div class="page-header">
<h2>Indlæg af <%= #user.first_name %></h2>
</div>
<% if current_user == #user %>
<%= render 'modal' %>
<% end %>
<%= render 'post' %>
I have attached the views in the gist underneath:
Gist: https://gist.github.com/czepluch/8166841
It makes no sense to me that this error occurs depending on the order the renders are placed in. So I would really like to know why the order of the rendering of the helpers matter?
Please add code to the question so it is saved with the answers here. I suspect it has to do with the fact that your form has this:
simple_form_for([#user, #user.posts.build]
That means a new post is built that has no attributes, which could cause a nil error later on. reverse the order, and this isn't built until after the other code has run. The only thing I can see at first glance that is related to datetime would be:
time_ago_in_words(p.created_at)
If created_at is nil, because of an empty post, that could generate an error.
Play with the form declaration, you may be able to do
simple_form_for([#user, :post])
or something like that to get a form for a new post without actually attaching an empty object to the #user object.
I am working on an application that involves "follow/unfollow" functionality. Users can follow Objects and Objects can have many Users following them. It's a has_many :through relationship via a Relationships model/controller.
I have the following snippet in the object#show view:
<% if current_user.following?(#object) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
When testing various functionalities in a request spec, it shows undefined method 'following?' for nil:NilClass and fails all of the object#show specs.
The following? method is in the User model and looks like this:
def following?(object)
relationships.find_by_object_id(object.id)
end
The method following? is in the User model (since they are the only ones doing following and unfollowing). I thought you could use methods between objects in Ruby, but perhaps not. If not, how would I go about refactoring this to be able to use that method?
Thanks in advance for any help!
There is no current_user helper in specs. That's why you get nil.
You should stab test user into current_user variable
Hey guys, I'm having trouble understanding a Rails construct. I'm using Rails 3 but I doubt this is specific to this version.
I have a model, Goal that has_many :commits and naturally, a Commit model that belongs_to :goal. I created the proper migration so that commits_table.references :goal.
I am actually going through the Rails Getting Started guide, except in that article they use a Post and Comment respectively.
Now that I've described the situation I can express my confusion. On the Goal's show view, I have embedded a form to create a new Commit which is 'attached' to the currently viewed Goal. This works fine and all. However, I am having trouble understanding why we do this
<%= form_for([#goal, #goal.commits.build]) do |f| %>
Shouldn't it be form_for(#commit)? I understand why we want the #goal, to provide some context since the commit is a nested resource. However, in the actual generated source, the form is appropriately named as commit, that is, the fields are named commit_blah. How did Rails know this? I understand that there's this whole system of "trust and magic" and all, but I mean at least at the high level, what from this code hinted to Rails that I wanted a commit?
I looked at the documentation for form_for and it seems like one of the parameters could be the action to take for the form. I imagine that in this case, that's what the #goal.commits.build parameter is for? To designate the action to take? Is this how Rails deduces that I want a commit? Would this also explain why this form is handled by the Commit controller even though this code is in the Goal's view?
Also, why are these parameters passed as an array ([])? In Ruby, will the method still just take it as two separate parameters, or is there a reason why this was passed this way?
Finally, rails generate automatically gave me some error showing code in my other _form.html.erb partials:
<% if #commit.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#commit.errors.count, "error") %> prohibited this commit from being saved:</h2>
<ul>
<% #commit.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
If I want to add this to this embedded form, how would I do so? I guess my question is, what would I use in place of #commit?
Thanks. I'm just trying to get my head around these new concepts.
If you go back to the documentation and click 'show source', you'll see
def form_for(record_or_name_or_array, *args, &proc)
...
case record_or_name_or_array
when String, Symbol
...
when Array
object = record_or_name_or_array.last
object_name = options[:as] || ActiveModel::Naming.singular(object)
apply_form_for_options!(record_or_name_or_array, options)
args.unshift object
else
...
end
...
output << fields_for(object_name, *(args << options), &proc)
...
For form_for, the first parameter can be a record, name or an array. In your case, you pass it an array. The code then determines the 'object' as the last member of that array, which is your #goal.commits.build object. The object name is determined from the ActiveModel::Naming.singular method.
console > ActiveModel::Naming.singular(#goal.commits.build)
=> "commit"
Then it generated the appropriate form fields using fields_for and 'commit'.
It looks like you are using nested resources. Check your routes.rb file to see if you have something like:
map.resources :commits, :has_many => :goals
or perhaps:
map.resources :commits do |commit|
commit.resources :goals
end
If that is the case, then you will need to supply both the commit and goal objects to the form_for method.