Hey all, I have been away from rails for a while and have been catching up to rails 3, I think my problem might stem from me using an unsupported syntax from rails 2 that didnt make it to rails 3. Anyways, my problem might be to broad but while I have been able to fix all the other problems with this app, this one still puzzles me.
On the home page of the site there is this code:
<%- unless #requested_contacts.empty? -%>
<h2>Contact Requests</h2>
<ul class="list requests small">
<%- #requested_contacts.each do |contact| -%>
<%- conn = Connection.conn(current_user, contact) -%>
<li>
<p><%= person_link contact %></p>
<p class="meta published">
<%= time_ago_in_words(conn.created_at) %>
ago
</p>
<p>
<%= link_to "Respond", edit_connection_path(conn) %> |
<%= link_to "View profile", contact %>
</p>
</li>
<%- end -%>
</ul>
<%- end -%>
When I click respond instead of getting to the Connection edit page, I get an error:
undefined method `contact' for nil:NilClass
app/controllers/connections_controller.rb:15:in `edit'
{"id"=>"4"}
The controller code is:
def edit
#contact = #connection.contact
end
The relavent models are, Person.rb:
has_many :connections
has_many :contacts, :through => :connections, :order => 'people.created_at DESC'
has_many :requested_contacts, :through => :connections, :source => :contact
Connection.rb:
belongs_to :person
belongs_to :contact, :class_name => "Person", :foreign_key => "contact_id"
def conn(person, contact)
find_by_person_id_and_contact_id(person, contact)
end
The edit page I am trying to get to is:
<h2>Contact request</h2>
<p>You have a contact request from <%= #contact.name %></p>
<% form_for(#connection) do |f| %>
<p>
<%= f.submit "Accept", :class => "button" %>
<%= f.submit "Decline", :id => nil, :class => "button" %>
</p>
<% end %>
I think that is all the relevant code to this issue. If there is anything else you might need to see please let me know, I am very grateful for any an all help. Sorry if it is glare lying obvious, I am learning ruby and rails as a hobby (and loving it so far!).
When you see this error:
undefined method `contact' for nil:NilClass
It usually means you're trying to call a method on an unassigned variable. Since the error points to the controller, and the code you've shown us is:
def edit
#contact = #connection.contact
end
I'm going to guess that #connection is unassigned. Normally you would expect to have a finder method to retrieve the value before using it, like:
#connection = Connection.find(params[:id])
Sometimes this code is placed in a before_filter, to reduce duplication. If you do have such a filter, perhaps it is not being reached. It's hard to know without seeing the rest of the controller code.
The problem is that you seem to have mixed things up. In your controller's edit method, you reference #connection which hasn't been instantiated as far as we know, like zetetic said, so it's nil, then you try to call a method on it. It seems we need even more information.
I believe your def conn(person, contact) should be a class method: def self.conn(person, contact), based on the way you are calling it (not from an object but directly from the class).
Basically, the problem is that conn is coming up as nil, I believe it's for the reason I mentioned above, but if not, then figuring out why will find you your answer.
EDIT: If you are still getting the same error, then I recommend you try this out in the rails console.
Connection.find_by_person_id_and_contact_id(person, contact)
Try and use the same information you are using in the form which is generating the error. Most likely the problem is that there is no connection between the person and the contact. If you are sure there is but the above method says otherwise, then there is most likely an issue with how you set up your associations. Remember that not only do you have to specify the association in the class but you also have to modify the tables accordingly to reflect the association.
Assuming your associations are OK, and person references a connection.
Replace this line <%- conn = Connection.conn(current_user, contact) -%> with <%- conn = #person.conn(current_user, contact) -%>
Related
I'm creating a application using ruby on rails, but currently i'm suffering a problem like db relation, below my code:
Company
has_many :posts, :foreign_key => :company_id
Post
belongs_to :companies, :foreign_key => :company_id
controller
#post = current_user.companies.all
view
<% #post.each do |p| %>
<%= p.posts.post_title %>
<% end %>
Showing error above code.
If I debug like use <%= debug p.posts %> then showing all posts, which is under my companies but when I use <%= debug p.posts.post_title %> then showing ActiveRecord_Associations_CollectionProxy:0x0000000e490b98
Thanks
I think the problem here is that you are trying to call the method :post_title on p.posts, which is an ActiveRecord::Associations::CollectionProxy object.
In your example, p is a Company object, which has a method posts, which returns to you a CollectionProxy object that acts a lot like a list of posts. That list will not have a method post_title, but each element of that list will have a method post_title
So, instead of
<% #post.each do |p| %>
<%= p.posts.post_title %>
<% end %>
You will want something like:
<% #post.each do |company| %>
<% company.posts.each do |post| %>
<%= post.post_title %>
<% end %>
<% end %>
Two additional things to note:
1) The variable #post is inaccurately named. Inaccurate variable names will lead to confusion when trying to understand what is happening. current_user.companies.all returns a list of companies, and therefore, it should read:
#companies = current_user.companies.all
not
#post = current_user.companies.all
2) The actual error that is being shown to you likely says something like
Undefined Method 'post_title' for ActiveRecord_Associations_CollectionProxy:0x0000000e490b98
Not just
ActiveRecord_Associations_CollectionProxy:0x0000000e490b98
When debugging and asking for help, it's very important to note the entire message of the exception being raised.
Because companiy has_many :posts........ posts are objects you need a loop to show all posts e.g
p.posts.each do |post|
I get an error undefined method 'email' for nil:NilClass when I try to access a post with a comment from a user that has been deleted in the DB.
I wonder: how can I remove the comments that has been created by users who no longer exists "on the fly"?
I tried something like this
<%= div_for(comment) do %>
<% if comment.user.email.nil?%>
<% comment.destroy %>
<%else%>
<p><%= comment.body %></p>
<p class="comment-submitted-by"><%= time_ago_in_words(comment.created_at) %> ago by
<%= comment.user.email %></p>
<%end%>
but I still get the error.
You're still getting an error because you've referenced comment.user.email, and user is nil. You need to check comment.user.nil?, or you're also at risk for deleting a comment just because a user's email is missing (though maybe you disallow that):
<% if comment.user.nil? %>
<% comment.destroy %>
Cleaning up on the fly is going to be finicky and cumbersome. What it looks like you want is dependent: :destroy on your User#comments association.
class User
has_many :comments, dependent: :destroy
end
Then when your User is removed, all of their Comments will be too, and you don't have to worry about it at display time.
Since there are existing orphaned comments, you can clean them out with a simple SQL statement:
DELETE FROM comments WHERE user_id NOT IN (
SELECT id FROM users
)
Or your Rails console:
Comments.find_each { |c| c.destroy if c.user.nil? }
Removing some comments from a thread might make it hard to understand the remaining comments, because of missing context.
Therefore I would like to suggest another approach: Just display deleted user instead of the user's email when the user was deleted.
A simple implementation might look like this:
<%= div_for(comment) do %>
<p><%= comment.body %></p>
<p class="comment-submitted-by">
<%= time_ago_in_words(comment.created_at) %> ago by
<%= comment.user ? comment.user.email : 'deleted user' %>
</p>
<%end%>
I am making an app in Rails 4.
I have an address model, which is polymorphic.
My associations are:
profile.rb
has_many :addresses, as: :addressable
address.rb
belongs_to :addressable, :polymorphic => true
In my address.rb, I have a method for:
def country_name
self.country = ISO3166::Country[country]
country.translations[I18n.locale.to_s] || country.name
end
In my profile views folder, I have a partial to display a user's country, as:
<span class="profilesideinfo">
<% if #addresses.country_name.present? %>
<%= #addresses.country_name.titlecase %>
<% else %>
<span class="profileeditlink">
<%= link_to "Add your location", new_address_path %>
</span>
<% end %>
</span>
I have also tried:
<% if #profile.addresses.country_name.present? %>
<%= #profile.addresses.country_name.titlecase %>
<% else %>
<span class="profileeditlink">
<%= link_to "Add your location", new_address_path %>
</span>
<% end %>
And I have also tried (changing country_name (which is the method in my model) to country (which is the attribute in my address table))
Im getting stuck, because I can successfully create an address, but then that country name should show in the profile show partial. It doesn't. Instead, I get an error that says:
undefined method `country_name' for nil:NilClass
Is there something else that needs to happen for a reference to a polymorphic instance to show in the parent.
Can anyone see what needs to happen to get this to work?
I have tried making a scope in my profile model as:
Profile.joins(:addresses).where("addresses.profile_id = ?", profile_id)
I'm not sure this is adding any value. I'm not sure how to use it or whether it works, given that the address model doesn't have a foreign key for profile_id.
When I save this and try to reload the page, I get this error:
undefined local variable or method `profile_id' for #<Class:0x007fbacaec2d18>
Taking SurreyMagpie's suggestion below, I change the partial to:
<% if #profile.addresses.country_name.any? %>
<%= #profile.address.country_name.first.titlecase %>
<% else %>
<span class="profileeditlink">
<%= link_to "Add your location", new_address_path %>
</span>
<% end %>
I am checking if there are any addresses and then displaying the first country name.
When I try this, I get this error:
undefined method `country_name' for #<ActiveRecord::Associations::CollectionProxy []>
The polymorphic nature of the association is not responsible for your difficulties here.
When you define country_name as a method in your Address class, that is known as an instance method. As such, you are able to call it on a single Address object. So, if in the rails console you run Address.first.country_name you should receive a result for that specific instance of Address.
However, when you query a has_many association, in your case #profile.addresses, you get an ActiveRecord::Associations::CollectionProxy returned, even if there is only a single Address record. It is not exactly an array but has very similar behaviour.
The point is: you cannot call your instance method on the whole set at once. You need to iterate through the collection and call the method on each instance. For example:
<% if #profile.addresses.any? %>
<% #profile.addresses.each do |address| %>
<span class="profilecountry">
<%= address.country_name.titlecase %>
</span>
<% end %>
<% else %>
<span class="profileeditlink">
<%= link_to "Add your location", new_address_path %>
</span>
<% end %>
may be what you need - though how you choose to display multiple countries is up to you.
I have a very concrete dilemma right now.
Given the following models:
class Message < ActiveRecord::Base
attr_accessible :body, :sent_at
belongs_to :subject
end
class Subject < ActiveRecord::Base
attr_accessible :title
has_many :messages
belongs_to :last_message, :class_name => 'Message', :foreign_key => 'last_message_id'
end
In a view I want to iterate over a list of subjects and display:
- Subject title
- sent_at for the subject's last message
like this:
<% #subjects.each do |subject| %>
<%= subject.title %>
<%= subject.last_message.sent_at %>
<% end %>
The thing is: subject.last_message may some times be nil. In which case, the above code will throw an exception.
So: What is the best solution to this? I can see 3 possibilities, but honestly don't know which are considered good or bad.
1) Let the view rescue it
<%= subject.last_message.sent_at rescue '' %>
2) Make a helper
def last_message_sent_at(subject)
return '' if subject.last_message.blank?
subject.last_message.sent_at
end
<%= last_message_sent_at(subject) %>
3) Make a sort of "proxy" on the Subject model
class Subject < ...
...
def last_message_sent_at
return '' if last_message.blank?
last_message.sent_at
end
end
<%= subject.last_message_sent_at %>
Which would you choose, and why? Or is there perhaps another way, which I haven't thought about?
/ Carsten
Use try :
<%= subject.last_message.try(:sent_at) %>
So, if subject.last_message is nil, you will get no output; else if it is not nil, it will call the method sent_at on subject.last_message.
It is like a convenient form for your #2 idea
Documentation
As additional thought, helper is a bad choice. You ideally always want a "receiver" (in some_class.perform(), some_class is the "receiver" i.e. it "receives" the message "perform"). I avoid Helpers unless I need to generate HTML. So, your #3 does have a receiver, but since Rails provides try, you do not need to roll your own.
The easiest thing, in this case, may be to simply check for the null value...
<% #subjects.each do |subject| %>
<%= subject.title %>
<%= subject.last_message.sent_at if subject.last_message %>
<% end %>
or
<% #subjects.each do |subject| %>
<%= subject.title %>
<%= subject.last_message && subject.last_message.sent_at %>
<% end %>
If you had any logic or action to perform, best practice would be to move it out of your views (into helpers, presenters).
Since your question is about "how to call a method on possibly nil instance?", then try is probably the best way to go in this case. Because, it's already there and you don't need any extra gems.
On the other note, you can improve your code by just putting render #subjects and moving your block content into the _subject parcial. Rails will do the looping for you.
Article HABTM authors
In Article model, i say:
validates_associated :authors
But, by creating of the new Article, this validation does't happen, because i don't see the errors.
Another errors are displayed properly, but this.
I render errors so:
<div class="errors">
<%= article_form.error_messages %>
</div>
What's wrong here ?
Validates_associated should work with any kind of association.
Try to display your errors either with:
<%= #article.errors.full_messages.to_sentence %>
or
<%- for author in #article.authors %>
<%= author.errors.full_messages.to_sentence %>
<%- end %>