I am using gem devise for creating users profile
Each user can create a comment. I need to add the user name beside each comment something like this <%= #comment.user.name %>
in user.rb
has_many :comments, dependent: :destroy
in comment.rb
belongs_to :users
in comment controller
before_action :find_comment ,only:[:show,:update,:edit,:destroy]
def new
#user =User.find(params[:id])
#comment = #user.comments.build
end
def create
#user =User.find(params[:id])
#comment = #user.comments.build(comment_params)
#comment.user = current_user
if #comment.save
redirect_to doctor_path(:id => #user.id)
end
end
private
def find_comment
#comment = Comment.find(params[:id])
end
def comment_params
params.require(:comment).permit(:text)
end
user controller
def show
#user = User.find(params[:id])
end
user show.html.erb
<% for item in #user.comments %>
<% if item.text.present? %>
<%= item.text %><br>
<%= #comment.user.name %>
<br><hr>
<% end %>
I got this error
undefined method `user' for nil:NilClass
You could do it the other way around, in your show method:
#comments = Comment.all
in your show view:
<% #comments.each do |comment| %>
<%= comment.text %>
<%= comment.user.name %>
<% end %>
Since your question is not really clear I'll specifiy that if you want to show just the comments posted by the user:
def show
user_id = User.find(params[:id]).id
#comments = Comment.where(user_id: user_id)
end
Just some quick rules to start with
A user has many comments, this will be the relationship between the user and a comment that the user has made.
You already have this
A user has many profile comments, this is the relationship between a user and the comments that have been left for that user on their profile
Now you have that distinction things start to be come clearer.
Start by creating a single xref table to act as the go between users and comments that have been left for a profile and call it profile_comments
this profile_comments table needs a user_id and a comment_id of type integer to store the primary keys from user and comments tables, where the user_id is the id of the user that is having a comment left about them on their profile
You can now setup a profile_comment model that with the following relationships
belongs_to comment
belongs_to user
So now you need to change your user model relationships to the following
user.rb
has_many :comments
has_many :profile_comments, dependent: :destroy
comment.rb
belongs_to :user #not users as you have defined in your question
has_many :profile_comments, dependent: :destroy
and the new profile_comment.rb model needs the two belongs_to clauses for comment and user
profile_comment.rb
belongs_to :user
belongs_to :comment
Now when you create a comment you need to assign to to the user, and also to the profile_comment
So now your comments controller needs to setup these relationships so instead of
before_action :find_comment ,only:[:show,:update,:edit,:destroy]
def new
#user =User.find(params[:id])
#comment = #user.comments.build
end
def create
#user =User.find(params[:id])
#comment = #user.comments.build(comment_params)
#comment.user = current_user
if #comment.save
redirect_to doctor_path(:id => #user.id)
end
end
You need something like this
def create
#user =User.find(params[:id])
#comment = current_user.comments.build(comment_params)
#profile_comment = ProfileComment.new
#user.profile_comment < #profile_comment
#comment.profile_comment < #profile_comment
if #comment.save
redirect_to doctor_path(:id => #user.id)
end
end
Your update action will need to also change accordingly
Now in your view instead of
<% for item in #user.comments %>
<% if item.text.present? %>
<%= item.text %><br>
<%= #comment.user.name %>
<br><hr>
<% end %>
<% end %>
You want this, it's a little complex because you need to get from the profile comment to the comment then to the user that created the comment
<% #user.profile_comments.each do | profile_comment |%>
<%comment = profile_comment.comment%>
<% if comment.text.present? %>
<%= comment.text %><br>
<%if comment.user.blank?%>
No user assigned to this comment
<%else%>
<%= comment.user.name #or email or whatever%>
<%end%>
<br><hr>
<% end %>
<% end %>
Although text is a reserved word and is an actual column type so you might want to change the column name text to something else
Any questions on this feel free to get back to me but I won't be around for the next 24 hours. Hope it's clear and helps you understand what has gone wrong with your initial setup
In the controller and the view I have assumed that the current_user is the person making the comment and #user is the person that is being commented on. Just switch that round if I have that wrong
Related
#user.name works on my posts, user profile, and everywhere else on my site. But when I add it to user comments, I get undefined method?
<p class="comment_body">
<h2><%= #user.name %></h2>
<%= comment.body %>
</p>
I tried <%= user.name %> and still an error.
I tried <%= current_user.name %> and it worked. However, I don't want to show the current user's name, I want to see the user's name of who posted the comment.
EDIT:
I forgot to associate user to comment, but I'm not really sure how.
Comments controller
class CommentsController < ApplicationController
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create(params[:comment].permit(:body))
redirect_to post_path(#post)
end
end
I went into my comments.rb and wrote belongs_to :user and in my user.rb I added has_many :comments.
So, should you set the user and save the comment, shouldn't you? try something like
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create(params[:comment].permit(:body))
#comment.user = current_user
if #comment.save
redirect_to post_path(#post)
else
# something else
end
end
Currently I have a Subscriber model and Comments model that belongs to Subscriber. Right now I need to link two models together so that my Subscriber has many comments on it. what I want is so that if I write this in the console I'll get my answer -> Subscriber.find(1).comments.first right now that returns nil because it doesn't know how to find the id of the subscriber that is leaving the comment. How can I give the application the proper code so that I can link the two? I'll post code for clarity.
CONTROLLER:
class CommentsController < ApplicationController
def new
#comment = Comment.new
end
def create
#subscriber = Subscriber.find(params[:subscriber_id])
#comment = #subscriber.comments.build(comments_params)
if #comment.save
flash[:notice] = "Thank you!"
redirect_to subscribers_search_path(:comments)
else
render "new"
end
end
private
def comments_params
params.require(:comment).permit(:fav_drink, :subscriber_id)
end
end
As you can see I'm trying to find the :subscriber_id when I create the comment. That is where my problem is. How can I connect it
ERROR:
MODELS:
class Comment < ActiveRecord::Base
belongs_to :subscriber
end
class Subscriber < ActiveRecord::Base
has_many :comments
end
Another aspect I should be clear about is that I have no current subscriber because this app is used for checking in a customer so the app does not log the user in it just checks them in with their phone number. Let me know if you need more info.
VIEWS:
<h1>new</h1>
<%= form_for #comment do |form| %>
<div class="form-group">
<p>
<%= form.label :fav_drink %>
<%= form.text_field :fav_drink %>
<%= form.hidden_field :subscriber_id %>
</p>
<%= form.submit "Send", class: "btn btn-primary" %>
</div>
<% end %>
Method 1
You subscriber id is inside the comment hash in your params. So you need to find subscriber like this
#subscriber = Subscriber.find(params[:comment][:subscriber_id])
#If you're taking this approach, you need to remove :subscriber id from your comment_params
Lik this
def comment_params
params.require(:comment).permit(:fav_drink)
end
##subscriber.comments.build will take care of the subscriber_id field for you, so its pointless rewriting it
Method 2
Or you directly create your comment.
#comment = Comments.new(comments_params)
#notice this already has, the subscriber_id, so we don't need to find
#subscriber and then do build on it
Let me know if that helps
I'm learning and trying to add functionality to a simple app. I'm adding a comments ability to each micropost and creating comments works fine, however the comments will not render. No error message, application runs perfectly fine except the comments partials just isn't included in the final view.
I've looked at similar questions here and tried so many solutions that I'm not even sure where the problem might be, any help would be much appreciated.
I have 3 relevant models: Users, Microposts, Comments.
Microposts belong to Users, has_many comments.
Comments belongs to Microposts and Users.
Comments model includes columns for "comment_content", "micropost_id", "user_id" and "created_at".
Micropost.rb
class Micropost < ActiveRecord::Base
belongs_to :user
has_many :comments, dependent: :destroy
default_scope -> { order(created_at: :desc) }
validates :user_id, presence: true
validates :content, presence: true, length: { maximum: 1000 }
acts_as_votable
Comment.rb
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :micropost
validates :comment_content, presence: true
validates :user_id, presence: true
validates :micropost_id, presence: true
User.rb
class User < ActiveRecord::Base
has_many :microposts, dependent: :destroy
has_many :comments
User Controller#show
def show
#user = User.find(params[:id])
#microposts = #user.microposts.paginate(page: params[:page])
#micropost = Micropost.find(params[:id])
#comment = Comment.new
#comments = Micropost.find(params[:id]).comments.paginate(page: params[:page])
end
Comments Controller#create
def create
#micropost = Micropost.find(params[:micropost_id])
#comment = Comment.new(comment_params)
#comment.micropost = #micropost
#comment.user = current_user
if #comment.save
flash[:success] = "Comment created!"
redirect_to current_user
else
render 'shared/_comment_form'
end
end
To render in view from _micropost partial
<ul>
<%= render #comment %>
</ul>
Comments partial _comments
<%= link_to gravatar_for(#micropost.user, size: 15), #micropost.user %>
<%= link_to #micropost.user.name, #micropost.user %>
<% #micropost.comments.each do |comment| %>
<%= comment.comment_content %>
<% end %>
The comments form displays just fine. After logging in and creating a comment I check the console and confirm a comment is created, has the correct content, is associated with the User that made the post and the micropost it was commented on.
So the comment is sitting there in the DB, it just won't come out!
SOLUTION
UsersController:
def show
#user = User.find(params[:id])
end
Views
<% #user.microposts.each do |micropost| %>
<%= link_to gravatar_for(#user, size: 15), #user %>
<%= link_to #user.name, #user %>
<% micropost.comments.each do |comment| %>
<%= comment.comment_content %>
<% end %>
<% end %>
That's basically it, I was overloading my UsersController#show and that was throwing the whole thing off. As the advice below states the Userscontroller was doing the heavy lifting, and I shouldn't have been defining so many variables there.
Can't express enough thanks to #thedanotto and #fylooi. They were both correct. All of the troubleshooting they walked me through taught me so much. It's intimidating learning Rails and I've always refrained from asking stupid questions online, but this experience showed me just how awesome some people can be! I've got a lot to learn, reading through the pragmatic programmers series, I'll do my best to give back to the community!
Your has_many and belongs_to relationships appear to be set up correctly. This means you can rely upon rails to do most of the heavy lifting in your controller and views.
User Controller#show becomes...
def show
#user = User.find(params[:id])
end
views/users/show.html.erb becomes...
<% #user.microposts.each do |micropost| %>
<%= link_to gravatar_for(#user, size: 15), #user %>
<%= link_to #user.name, #user %>
<!-- You have access to micropost here as well, you could still do micropost.user, micropost.user.name instead of #user -->
<% micropost.comments.each do |comment| %>
<%= comment.comment_content %>
<% end %>
<% end %>
this can't work
<%= micropost.comment.comment_content %>
you have a has_many relation in your micropost model.
you could solve this to add a has_one relation to your micropost model with an order by created_at
or temporary (really temporary)
<%= micropost.comments.last.comment_content %>
update:
your partial _comments just need to talk to the comment variable.
so change your micropost.comment.comment_content to comment.comment_content
the name of the user should delegate to the usermodel via
delegate :name, to: :user, prefix: true, allow_nil: true
in your comment model. now you can use comment.user_name to display the name of the user
best
A few things:
You're loading both User and Micropost in your UsersController#show based on ID. Doesn't look right to me, unless your User and Micropost database IDs move in lockstep.
#user = User.find(params[:id])
#micropost = Micropost.find(params[:id])
A Micropost should be shown in a MicropostsController, not a UsersController. Eg. /microposts/1 should return the first Micropost resource, while /users/1 returns the first User resource.
I'm going to assume you're trying to render the user's microposts and their related comments from UsersController#show
Based on that, your variable structure can be arranged as per the following:
# users_controller.rb
class UsersController
def show
#user = User.find(params[:id])
#microposts = #user.microposts
# better practice is to have only one # instance variable in the
# controller, but let's go with this for academic purposes
end
end
# views/users/show.html.erb
<%= render #microposts %>
# this can also be written as
# <% #microposts.each do |micropost|
# <%= render partial: 'micropost', locals: { micropost: micropost }
# <% end %>
# views/users/_micropost.html.erb
<%= link_to gravatar_for(micropost.user, size: 15), micropost.user %>
<%= link_to micropost.user.name, micropost.user %>
<ul>
<%= render micropost.comments %>
</ul>
# views/users/_comment.html.erb
<li>
<%= comment.content
</li>
I'm working on allowing a user to favorite a post.
I've created a model called favorite.
belongs_to :user
belongs_to :post
it stores the user_id and post_id.
I've also created a FavoritesController
class FavoritesController < ApplicationController
def create
#post = Post.find(params[:post_id])
current_user.favorite(#post)
end
def destroy
#post = Post.find(params[:id])
current_user.unfavorite(#post)
end
end
the form I have on my Posts#index is:
<%= form_for current_user.favorites.build do |favorite| %>
<%= hidden_field_tag :post_id, f.id %>
<%= favorite.button do %>
<i class="fa fa-star-o"></i>
<% end %>
<% end %>
my user model looks like this:
# Favorites a post.
def favorite(post)
favorite.create(post_id: post)
end
# Unfavorites a post.
def unfavorite(post)
favorite.find_by(post_id: post).destroy
end
when I try to click on favorite I get:
wrong number of arguments (0 for 1)
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"HjiANQUqTQVEqy0yzfLFMlnC8RsTiY5kVlvIUnD5OSIaSYSi4ELSuC95vRMIBA/6W+KvzCWMMXQ==",
"post_id"=>"7",
What am I doing wrong here? Also is there a better way to do this?
If you're just trying to get a 'voting/favoriting' system working, I suggest using a gem like https://github.com/ryanto/acts_as_votable or something of the like.
My Rails app allows users to create "connections" that describes their relationship with other users. Users can comment on other users' blog posts (called "works" here) and, for each comment made on a blog post, I want to show the users' relationship to the author. I'm having trouble creating the instance variable in the works controller.
Here's what I have so far in the show action in the works controller:
class WorksController < ApplicationController
def show
#work = Work.find(params[:id])
#workuser = #work.user_id
#connections = Connection.where(user_id: #workuser, otheruser_id: UNKNOWN).all
#comment = #work.comments.build
#comment.user = current_user
#comments = #work.comments.order("created_at DESC").where(work_id: #work).all
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #work }
end
end
end
I need help with the #connections instance variable, specifically what to assign the otheruser_id: parameter. I know for a fact that this needs to be the user_id of the user who posted a comment. However, I'm stumped as to how to get this id.
Here are the model relationships:
work.rb- belonts_to :user, has_many :comments
user.rb- has_many :works, has_many :comments, has_many :connections
connection.rb- belongs_to :user
Please let me know if I can provide any other information. Any help will be greatly appreciated!
Thanks!!
EDIT: Simplified version of the view code that populates the comments (the user, the relationship to the author, and the comment content):
<% #comments.each do |comment| %>
<%= link_to comment.user.full_name, comment.user if comment.user %>,
<%= #connections.description %>
<%= #comment.content %>
<% end %>
Ill update yo on the instance variable once you answer my comment. But Bachan's answer should do it if its two way.
EDIT:
After what you said about one way relationships I think you should not create #connections instance variable.
Instead define a method in the user.rb model like this:
def get_connection otheruser
Connection.where(:user_id=>self.id,:otheruser_id=>otheruser.id).first
end
Then in the view.....
So you wanna display all the comments like:
Commentator Name
Connection between commentator and work author
comment content
Alright to do that you can do this:
<% #comments.each do |comment| %>
<%= link_to comment.user.full_name, comment.user if comment.user %>
<%= #work.user.get_connection(comment.user).description unless #work.user.get_connection(comment.user).nil? %>
<%= comment.content %>
<% end %>
Controller:
class WorksController < ApplicationController
def show
#work = Work.find(params[:id])
#workuser = #work.user_id
#comment = #work.comments.build
#comment.user = current_user
#comments = #work.comments.order("created_at DESC")
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #work }
end
end
end
Please have a try with
#connections = Connection.where("user_id = ? OR otheruser_id = ?", #workuser, #workuser)