Passing the user information to the mailer - ruby-on-rails

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

Rails Setting Devise Username as attribute of comment

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

Passing in, retrieving, and setting restrictions of User from Post - Comment model in Rails

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

Add Comment to User and Post models (Ruby on Rails)

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

Rails undefined method 'each' for nil:NilClass

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.

Rails: Update score of an user after he wrote a comment

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.

Resources