I have a Post which has many comments. I am trying to send a notification email to the owner of the post that someone has commented on their post but I am having a hard time trying to get the owner of the post to the mailer. the code if as follows
class CommentsController < ApplicationController
def create
#commentable = find_commentable
#comment = #commentable.comments.build(comment_params)
#comment.user_id = current_user.id
if #comment.save
flash[:notice] = "Successfully posted an offer."
PostMailer.comment_posted(----).deliver #this is the mail code
redirect_to #commentable
else
flash[:error] = "Error adding an offer."
end
end
end
below is the mailer code
class PostMailer < ActionMailer::Base
default from: "contact#example.com"
def comment_posted(user)
#user = user
mail to: user.first_name, subject: "You have a new Comment!"
end
end
below is the comment model
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :commentable, :polymorphic => true
has_ancestry
end
and the Post model
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments, :as => :commentable, dependent: :destroy
end
Use this:
PostMailer.comment_posted(#commentable.user).deliver
#commentable will give you corresponding Post record for the given comment. Post belongs_to a user, so you can access the poster using #commentable.user.
I noticed in the controller you are doing:
PostMailer.comment_posted
Shouldn't this be:
PostMailer.offer_posted(#comment.user).deliver
?
Related
I'm new to rails and still figuring out which things belong in the model and which in the controller. I'm creating a simple comment model that belongs to articles. I have a attribute :commenter which is a string. I would like to get the username from the current_user (I'm using devise for my login feature) Would I do this in the create method of my controller?
Something like
def create
#post = Post.find(params[:post_id])
#comment.commenter = current_user.username
#comment = #post.comments.create(comment_params)
redirect_to post_path(#post)
end
class User < ActiveRecord::Base
has_many :posts
has_many :comments
end
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :user #should have user_id: integer in Comment
belongs_to :post #should have post_id: integer in comment
delegate :username, to: :user, allow_nil: true
end
In posts controller: -
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.new(comment_params)
#comment.user = current_user
if #comment.save
flash[:success] = "Comment saved successfully!"
redirect_to post_path(#post)
else
flash[:error] = #comment.errors.full_messages.to_sentence
redirect_to post_path(#post)
end
end
After that you can get all user details of any comment:-
comment = Comment.find(#id_of_comment)
comment.username => #will return username because of delegation
Reference for delegation
I'm attempting to set limits on the amount of commenting users can do on particular post during the day. I have implemented the following (successfully) in my Post model to limit the amount of Posts they can create.
class Post < ActiveRecord::Base
validate :daily_limit, :on => :create
def daily_limit
# Small limit for users who just sign up
if author.created_at >= 14.days.ago
if author.created_posts.today.count >= 4
errors.add(:base, "Exceeds Your Daily Trial Period Limit(4)")
end
else
if author.created_posts.today.count >= author.post_limit_day
errors.add(:base, "Exceeds Your Daily Limit")
end
end
end
end
But, when I attempt to add similar restrictions to my Comment model
class PostComment < ActiveRecord::Base
validate :daily_limit, :on => :create
belongs_to :post, :counter_cache => true
belongs_to :user
def daily_limit
# Small limit for users who just sign up
if user.posted_comments.today.count >= 2
errors.add(:base, "Exceeds Your Daily Trial Period Limit(4)")
end
end
end
I am greeted with a undefined method 'posted_comments' for nil:NilClass error. I don't believe my user_id is being passed into my model correctly in order to access it with something like user.posted_comments.today.count>=2
My create action in my post_comments controller is as follows:
class PostCommentsController < ApplicationController
def create
#post = Post.find(params[:post_id])
#post_comment = #post.post_comments.create(post_comment_params)
#post_comment.user = current_user
if #post_comment.save
redirect_to #post
else
flash[:alert] = "Comment Not Added"
redirect_to #post
end
end
end
and the my hacked down User model is as follows:
class User < ActiveRecord::Base
has_many :created_posts, class_name: 'Post', :foreign_key => "author_id",
dependent: :destroy
has_many :posted_comments, class_name: 'PostComment', :foreign_key =>"user_id", dependent: :destroy
end
Thanks.
You are assigning the user after "create" in your controller
#post_comment = #post.post_comments.create(post_comment_params)
#post_comment.user = current_user
Try this:
#post_comment = #post.post_comments.build(post_comment_params)
#post_comment.user = current_user
I'm new to Rails. I'm building my first app - simple blog. I have User and Post models, where each user can write many posts. Now I want to add Comment model, where each post can have many comments, and also each user can comment on any post created by any other user.
In Comment model I have
id \ body \ user_id \ post_id
columns.
Model associations:
user.rb
has_many :posts, dependent: :destroy
has_many :comments
post.rb
has_many :comments, dependent: :destroy
belongs_to :user
comment.rb
belongs_to :user
belongs_to :post
So how do I correctly define create action in CommentsController?
Thank you.
UPDATE:
routes.rb
resources :posts do
resources :comments
end
comments_controller.rb
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create(comment_params)
if #comment.save
redirect_to #post
else
flash.now[:danger] = "error"
end
end
The result is
--- !ruby/hash:ActionController::Parameters
utf8: ✓
authenticity_token: rDjSn1FW3lSBlx9o/pf4yoxlg3s74SziayHdi3WAwMs=
comment: !ruby/hash:ActionController::Parameters
body: test
action: create
controller: comments
post_id: '57'
As we can see it doesnt send user_id and works only if I delete validates :user_id, presence: true string from comment.rb
Any suggestions?
In your way you should put this:
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create(comment_params)
#comment.user_id = current_user.id #or whatever is you session name
if #comment.save
redirect_to #post
else
flash.now[:danger] = "error"
end
end
And also you should remove user_id from comment_params as strong parameters .
Hope this will help you .
Associations
To give you a definition of what's happening here, you have to remember whenever you create a record, you are basically populating a database. Your associations are defined with foreign_keys
When you ask how to "add comments to User and Post model" - the bottom line is you don't; you add a comment to the Comment model, and can associate it with a User and Post:
#app/models/comment.rb
Class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :post
end
This prompts Rails to look for user_id and post_id in the Comment model by default.
This means if you wanted to create a comment directly, you can associate it to either of these associations by simply populating the foreign_keys as you wish (or use Rails objects to populate them)
So when you want to save a comment, you can do this:
#app/controllers/comments_controller.rb
Class CommentsController < ApplicationController
def create
#comment = Comment.new(comment_params)
end
private
def comment_params
params.require(:comment).permit(:user_id, :post_id, :etc)
end
end
Conversely, you can handle it by using standard Rails objects (as the accepted answer has specified)
Class CommentsController < ApplicationController
before_action :set_user
before_action :set_post
def create
#comment = #post.comments.create(comment_params)
if #comment.save
redirect_to #post
else
flash.now[:danger] = "error"
end
end
private
set_post
#post = User.posts.find(params[:post_id])
end
set_user
#user = User.find(params[:user_id])
end
comment_params
params[:comment].permit()
end
I'm setting up an internal messaging system in my rails app and I'm having trouble getting the message to actually send to another user.
class User < ActiveRecord::Base
# messages and conversations
has_many :user_conversations
has_many :conversations, through: :user_conversations
has_many :messages
class UserConversation < ActiveRecord::Base
belongs_to :user
belongs_to :conversation
before_create :create_user_conversations
accepts_nested_attributes_for :conversation
delegate :subject, to: :conversation
delegate :users, to: :conversation
attr_accessor :to
private
def create_user_conversations
to.each do |recip|
recipient = User.find(recip)
UserConversation.create(user_id: recip, conversation_id: 1)
end
end
end
class Conversation < ActiveRecord::Base
has_many :user_conversations
has_many :users, through: :user_conversations
has_many :messages
accepts_nested_attributes_for :messages
class Message < ActiveRecord::Base
belongs_to :user_conversation
belongs_to :user
And here is my user_conversation_controller:
class UserConversationsController < ApplicationController
def new
#user = User.find(params[:user_id])
#conversation = #user.user_conversations.build
#conversation.build_conversation.messages.build
end
def create
#conversation = UserConversation.new(conversation_params)
#conversation.user = current_user
#conversation.conversation.messages.first.user = current_user
if #conversation.save
redirect_to user_conversation_path(current_user, #conversation)
else
flash[:error] = "There was an error"
render 'new'
end
end
private
def conversation_params
params.require(:user_conversation).permit(:to => [],
conversation_attributes: [:subject,
messages_attributes: [:body]])
end
The error comes in the create_user_conversations method in the UserConversation model. When I try to run
to.each do |recip|
I get an "undefined method 'each' for nil:NilClass" error. However, the "to" array has a value in it, in this case the parameters looked like this:
{"utf8"=>"✓",
"user_conversation"=>{"to"=>["2"],
"conversation_attributes"=>{"subject"=>"Hey",
"messages_attributes"=>{"0"=>{"body"=>"hey"}}}},
"commit"=>"Create User conversation",
"user_id"=>"1"}
Any ideas on why that array isn't getting passed in correctly? Thanks.
You define to as an attr_accessor, which will create get/set methods for an instance variable #to. You're using to as a local variable in your private method create_user_conversations though. This explains the nil:NilClass error.
Try changing the local variable to be an instance variable instead.
I solved my problem by going ahead and adding a recipients_id column to my user_conversations table, then in my UserConversations controller I was able to do
def create
#conversation = UserConversation.new(user_conversation_params)
#conversation.user = current_user
#conversation.conversation.messages.first.user_id = current_user.id
if #conversation.save
UserConversation.recipient_id = #conversation.recipient_id
redirect_to user_conversation_path(current_user, #conversation)
create_user_conversations
else
flash[:error] = "There was an error"
render 'new'
end
end
With the private method create_user_conversations also in my UserConversations controller:
def create_user_conversations
UserConversation.recipient_id.each do |recip|
recipient = User.find(recip)
UserConversation.create(user: recipient, conversation: #conversation.conversation)
end
end
I doubt this is the most elegant way to do this, but it at least gets the job done.
i'm really new to Rails and i'm wondering, how the following could be done:
After an user has written a comment for a sin ( =article), the author ( =user) should get 20 points (for example) added to his score (= user.score). score is a column in my Users table.
My models look like this:
class User < ActiveRecord::Base
has_many :comments, :dependent => :destroy
has_many :absolutions, :dependent => :destroy
end
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :sin
end
class Sin < ActiveRecord::Base
has_many :comments, :dependent => :destroy
end
My comments controller looks like this:
class CommentsController < ApplicationController
def new
#comment = Comment.new
end
def create
#sin = Sin.find(params[:sin_id])
#comment = current_user.comments.build(params[:comment])
#comment.sin_id = #sin.id
if #comment.save
flash[:success] = "Comment created!"
redirect_to sin_path(#sin)
else
flash[:error] = "Comment was not created."
redirect_to sin_path(#sin)
end
end
end
After spending several hours to get this on my own, i'm a little confused. After creating a comment, i would like change a specific value of the associated object User.
What would be the best way to do this?
Thanks for your help!
You could just add it after save :
if #comment.save
flash[:success] = "Comment created!"
current_user.score += 20
current_user.save
redirect_to sin_path(#sin)
else
BUT, it's always better to do it in your model. So i would create an add_score instance method in your user model and update the score there. Then, i would just call that method in the controller, in the same spot.
Define an after_save callback in your comment model:
class Comment < ActiveRecord::Base
[...]
after_save :add_score
private
def add_score
self.user.score += 20
self.user.save
end
end
You could use an after_create callback in your comment model that makes the change in the corresponding user?
This kind of logic doesn't belong in the controller.