I have tried setting up a comment system on my application. I have made a migration for the comments so all the comments have a user_id and post_id referenced with them. I have added has_many :comments, through: :posts in my user model. I have also added has_many :comments in my posts controller. In my comments controller I have also added belongs_to :post and the same for belongs_to :user. The problem occurs though when I try to call anything from the user model through an html.erb. When I make a comment through the console everything goes through fine and I can see what user made the comment, but when I try to even display any comments everything go sideways. Here is the part which is causing the error:
<% #comments.each do |comment| %>
<h3><%= comment.user.username %></h3>
<h4><%= comment.body %></h4>
</div>
<% end %>
It throws me an error in the username part giving me: undefined method `username' for nil:NilClass. Also, this occurs one every post even if that post doesn't have any comments. The body does work though.
undefined method `username' for nil:NilClass
This is caused by the fact that username is not a property of nil
You need to account for the fact that for some of your records, probably legacy data before you wrote the code to handle the associations, there is no user associated with a comment.
Change your view code to check for nil
<% #comments.each do |comment| %>
<h3><%= comment.user.username unless comment.user.blank? || comment.user.username.blank?%></h3>
<h4><%= comment.body %></h4>
</div> <%# why a random closing div here, remove it or move it to a more appropriate location to match an opening div%>
<% end %>
Or perhaps a little nicer
<% #comments.each do |comment| %>
<h3>
<%if comment.user.blank?%>
No user associated with this comment
<%= else comment.user.username.blank?%>
</h3>
<h4><%= comment.body %></h4>
</div> <%# why a random closing div here, remove it or move it to a more appropriate location to match an opening div%>
<% end %>
Root, because when you created comment, you did not set comment.user (example comment.user = current_user) before save.
Check your code in CommentsController -> method create
Related
I have two models here, Groups and Posts. Posts belong to group and groups have many posts. Here is my issue. I have an index page of groups. I'm trying to have a sidebar display a list of latest posts. I am unable to link to the posts because of the nested routes (I can't get the correct parameter for the group because this is all appearing on the group index page). Here is how I first tried to do it:
<% #latest_posts.each do |post| %>
<li><%= link_to post.title, group_post_path(#group, post) %></li>
<li><%= post.group.title %></li>
<% end %>
I've already looped through the list of groups on this same view, though:
<% #groups.each do |group| %>
<div class="table-cell">
<%= link_to group.title, group %>
</div>
<div class="table-cell">
<%= group.description.truncate(70) %>
</div>
<% end %>
So in my groups controller, I can't just make a #group instance variable to place into the group_post_path params. Here's my controller:
def index
#latest_posts = Post.order('created_at DESC').limit(20)
#groups = Group.order('created_at DESC').page(params[:page]).per(25)
end
So I have two problems. My main one is that I can't link to the post. I thought this would work, but no to that one also (I have friendly id set up, so I need to link to the group name instead of the id here.)
<%= link_to post.title, group_post_path(post.group_id, post) %>
But any attribute from the parent isn't available.
<%= post.group.title %>
produces
undefined method `title' for nil:NilClass
The same goes for trying it in the params.
<%= link_to post.title, group_post_path(post.group.title, post) %>
My models:
class Post < ApplicationRecord
belongs_to :group
class Group < ApplicationRecord
has_many :posts
How can I get at least access to the parent attributes?
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 know this is a really simple question, but I've gone completely blank! I'm reading through the Rails guides and looking at the getting started section. The following code is displaying all comments that belong to the current Post:
<h2>Comments</h2>
<% #post.comments.each do |comment| %>
<p>
<b>Commenter:</b>
<%= comment.commenter %>
</p>
<p>
<b>Comment:</b>
<%= comment.body %>
</p>
<% end %>
What is the simplest way of linking to each individual comment? For reference the page I am looking at is http://guides.rubyonrails.org/getting_started.html
The models are as follows:
class Post < ActiveRecord::Base
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :post
end
Rails will try to create route helpers to assist you in this. You can get a full list by running rake routes, but there are good odds that the one you'll be looking for is named comment_path:
<% #post.comments.each do |comment| %>
<%= link_to 'Click to view comment', comment_path(comment) %>
<% end %>
For reference, check out the Rails Routing Guide.
You should take a look to your routes, and see what's the path to an individual comment.
It should be something like : comment_path(comment) or post_comment(#post, comment)
You will link it with <%= link_to "View comment", comment_path(comment) %>