How do I pass commentable into mailer? - ruby-on-rails

I have this in the Model:
after_create do |comment|
CommentMailer.comment_email(self).deliver
end
This in CommentMailer:
class CommentMailer < ActionMailer::Base
helper ActionView::Helpers::UrlHelper
include CommentHelper
helper :comment
def comment_email(user, comment, commentable)
mail(to: user.email,
subject: "You have left a comment",
from: "comments#lumeo.com",
bcc: "brian#lumeo.com")
end
end
And this in CommentHelper:
module CommentHelper
def find_commentable
#comment = Comment.find(params[:comment])
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
end
I'm getting this error:
Started POST "/requests/6/comments" for 127.0.0.1 at 2012-11-30 17:28:55 -0800
Processing by CommentsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"R62NH5/EE34FPapEqy7mfpa0wKz18GtSdhH8MGYq2Ec=", "comment"=>{"content"=>"post", "show"=>"true"}, "commit"=>"Create Comment", "request_id"=>"6"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 2 ORDER BY users.created_at DESC LIMIT 1
Request Load (0.3ms) SELECT "requests".* FROM "requests" WHERE "requests"."id" = $1 LIMIT 1 [["id", "6"]]
CACHE (0.0ms) SELECT "requests".* FROM "requests" WHERE "requests"."id" = $1 LIMIT 1 [["id", "6"]]
(0.1ms) BEGIN
SQL (0.4ms) INSERT INTO "comments" ("commentable_id", "commentable_type", "content", "created_at", "show", "updated_at", "user_id") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id" [["commentable_id", 6], ["commentable_type", "Request"], ["content", "post"], ["created_at", Sat, 01 Dec 2012 01:28:55 UTC +00:00], ["show", true], ["updated_at", Sat, 01 Dec 2012 01:28:55 UTC +00:00], ["user_id", 2]]
(0.2ms) ROLLBACK
Completed 500 Internal Server Error in 136ms
ArgumentError (wrong number of arguments (1 for 3)):
app/mailers/comment_mailer.rb:5:in `comment_email'
app/models/comment.rb:27:in `block in <class:Comment>'
app/controllers/comments_controller.rb:22:in `create'

Looks like simple typos.
Line 7, as noted in the exception:
commentable = #comment.commentable
So, the issues:
You're calling #comment.commentabe, but #comment is nil
Hence the error: undefined method 'commentable' for nil:NilClass
#comment is nil in your mailer method because you're passing it in as comment NOT #comment, yet you're trying to reference it as #comment.
Also, why are you passing in commentable as a parameter, but on line 7 you're setting commentable again - this is redundant? Just use the already available commentable variable that you're passing in as a param. In fact, you seem to be doing this with several variables, yet I can't tell (because you don't show the mailer template) whether or not you're actually using them.
It could be that you could use something simpler like:
So, this should (probably) work:
def comment_email(user, comment, commentable)
mail(to: user.email,
subject: "You have left a comment",
from: "comments#lumeo.com",
bcc: "brian#lumeo.com")
end
If you post your mail template (so I can see what the body of the email looks like) I can help you get the variables into the template.

Related

Model create overrides custom params :created_at

I am uploading legacy articles to my Rails app. I am sending created_at as a parameter in my request as recommended in this answer. However, this attribute seemingly is not passed "through". I can puts(params[:created_at]) and see my custom created_at, yet in the logs the article is INSERTed with a created_at of the current timestamp.
Here is my articles controller:
class ArticlesController < ApplicationController
before_action :set_article, only: [:show, :update, :destroy]
...
# POST /articles
def create
#section = Section.friendly.find(params[:section_id])
# Can't let people publish by default
#article = #section.articles.build(
article_params.merge(is_published: false)
)
if #article.save
render json: #article, status: :created, location: #article
else
render json: #article.errors, status: :unprocessable_entity
end
end
end
My request is:
http POST :3000/articles title='example' section_id=1 content="<p>the section exists.</p>" slug="example" created_at="2017-06-109T17:57:55.149-05:00"
The logs:
Started POST "/articles" for 127.0.0.1 at 2017-11-24 12:05:06 -0500
Processing by ArticlesController#create as HTML
Parameters: {"title"=>"example", "section_id"=>"1", "content"=>"<p>the section exists.</p>", "slug"=>"example", "created_at"=>"2017-06-109T17:57:55.149-05:00", "article"=>{"title"=>"example", "slug"=>"example", "content"=>"<p>the section exists.</p>", "created_at"=>"2017-06-109T17:57:55.149-05:00", "section_id"=>"1"}}
Section Load (0.3ms) SELECT "sections".* FROM "sections" WHERE "sections"."slug" = $1 ORDER BY "sections"."id" ASC LIMIT $2 [["slug", "1"], ["LIMIT", 1]]
Section Load (0.4ms) SELECT "sections".* FROM "sections" WHERE "sections"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
(0.2ms) BEGIN
SQL (0.6ms) INSERT INTO "articles" ("title", "slug", "content", "is_published", "created_at", "updated_at", "section_id") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id" [["title", "example"], ["slug", "example"], ["content", "<p>the section exists.</p>"], ["is_published", "f"], ["created_at", "2017-11-24 12:05:06.175751"], ["updated_at", "2017-11-24 12:05:06.175751"], ["section_id", 1]]
(0.8ms) COMMIT
Completed 201 Created in 38ms (Views: 1.1ms | ActiveRecord: 8.0ms)
In my schema.rb:
create_table "articles", force: :cascade do |t|
...
t.datetime "created_at", null: false
My model has no extra methods/callbacks that would ruin the request. It only contains relationships. I don't know if this is relevant, but I saw it in a GitHub issue somewhere: articles and users are in a many2many with an authorships model, and I use devise to authenticate users.
In conclusion, the app is receiving the created_at param just fine, but it is overridden with the default timestamp. If I set record_timestamps to false, the created_at just becomes nil.
Why is my created_at just seemingly ignored?
Rails 5.1, Ruby 2.4.2, Postgres 10.1
Answer given by max: there was a syntatical error in my timestamp. It was not valid, and was ignored by Rails.

Suppress password change email when accepting invitation with Devise Invitable

I have enabled password change notifications using
config.send_password_change_notification = true
However, currently when a user accepts an invitation triggered by Devise Invitable they are receiving a password change email.
e.g.
Started PUT "/users/invitation" for 127.0.0.1 at 2017-10-20 16:14:41 +0100
Processing by UsersController::InvitationsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"9gDHF+Vm6oxGPILonaQe7NSnhytoQGsOBm0eVEMziSS6J93UFnoHSwouyV9NezleulmstfcNW8Axr/nJajBBYw==", "user"=>{"invitation_token"=>"98usw1XW4w31UuCd_DzQ", "full_name"=>"example", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Set my password"}
User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."invitation_token" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["invitation_token", "0a0787a3270a097c22a1272f49040c5c11d67b2cb222059d88d85f35e95c8d78"], ["LIMIT", 1]]
(0.2ms) BEGIN
SQL (0.6ms) UPDATE "users" SET "invitation_token" = $1, "encrypted_password" = $2, "full_name" = $3, "invitation_accepted_at" = $4, "updated_at" = $5 WHERE "users"."id" = $6 [["invitation_token", nil], ["encrypted_password", "$2a$11$qQKCx4FWQS2ARyiiGf8zdeAn7XLBa0clbWuv1cH1c1cXWbF65VMd6"], ["full_name", "example"], ["invitation_accepted_at", "2017-10-20 16:14:41.323768"], ["updated_at", "2017-10-20 16:14:41.324814"], ["id", 9]]
DeviseMailer#password_change: processed outbound mail in 1.7ms
Sent mail to example#example.com (195.9ms)
Is it possible to suppress the notification if the user is accepting an invitation but continue to send it for other password change events?
Environment info:
Rails 5.1.4
devise (4.3.0, 4.2.1)
devise_invitable (1.7.2)
thank you for pointing me in the right direction, here is my take on this
def send_password_change_notification
super unless accepting_invitation?
end
accepting_invitation? is a variable set on the beginning of the process
As a bonus, it bugged me that when you ask for a password recover it would prompt you with a success message and don't do anything, with this it would prompt with an error message.
[:en, :errors, :messages, :invitation_active] on your locales or just use default :not_found
def send_reset_password_instructions
if invited_to_sign_up?
self.errors.add :email, :invitation_active
else
super
end
end
OK, figured this out.
Add the following to app/models/user.rb
def send_devise_notification(notification, *args)
unless(notification == :password_change && sign_in_count.zero?)
super
end
end

nested attributes works for create but fails when update a record

I have a problem with nested attributes. Creating works but when I update, the error message shows me that the values in the relation are not set. I can't find the reason.
The main model
class Product < ActiveRecord::Base
has_many :product_options
accepts_nested_attributes_for :product_options,
:allow_destroy => true,
:reject_if => proc { | r | r["name"].blank? or r["value"].blank? }
end
The nested model
class ProductOption < ActiveRecord::Base
belongs_to :product
validates :name, :presence => true
validates :value, :presence => true
end
The controller is a bit shorted.
Items is a model where Product is related to as has_one
class Admin::ProductsController < Admin::ApplicationController
before_action :set_product, only: [ :new, :show, :edit, :update, :destroy ]
def create
#product = Product.new( product_params )
respond_to do |format|
if #product.save
#product.product_options.build
format.js { render :js => "alert( 'Daten gespeichert!' );" }
else
format.js { render :js => 'alert( "Fehler beim Speichern!" );' }
end
end
end
def update
respond_to do |format|
if #product.update( product_params )
format.js { render :js => "alert( 'Daten gespeichert!' );" }
else
require "pp"
pp #product.errors
format.js { render :js => 'alert( "Fehler beim Speichern!" );' }
end
end
end
private
# UPDATE: creating the product_options at this time
# produces the described error :)
def set_product
#item = Item.find_by_id( params[ :item_id ] ) if params[ :item_id ]
#product = #item.product ? #item.product : #item.build_product
# WRONG Place for generating new options
# 2.times { #product.product_options.build }
end
def product_params
params.require( :product ).permit( :item_id, :name, :title, :active, :product_options_attributes => [ :id, :name, :value, :_destroy ] )
end
end
The console output for the create is working and looks like
Started POST "/admin/items/653/product" for 127.0.0.1 at 2014-02-14 15:12:14 +0100
Processing by Admin::ProductsController#create as JS
Parameters: {"utf8"=>"✓", "product"=>{"item_id"=>"653", "name"=>"1", "title"=>"1", "active"=>"1", "product_options_attributes"=>{"0"=>{"name"=>"aaa", "value"=>"aaaa"}}}, "commit"=>"Create Product", "item_id"=>"653"}
User Load (1.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = 6 ORDER BY "users"."id" ASC LIMIT 1
(0.6ms) BEGIN
SQL (17.5ms) INSERT INTO "products" ("created_at", "item_id", "name", "title", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["created_at", Fri, 14 Feb 2014 14:12:14 UTC +00:00], ["item_id", 653], ["name", "1"], ["title", "1"], ["updated_at", Fri, 14 Feb 2014 14:12:14 UTC +00:00]]
SQL (1.3ms) INSERT INTO "product_options" ("created_at", "name", "product_id", "updated_at", "value") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["created_at", Fri, 14 Feb 2014 14:12:14 UTC +00:00], ["name", "aaa"], ["product_id", 28], ["updated_at", Fri, 14 Feb 2014 14:12:14 UTC +00:00], ["value", "aaaa"]]
Item Load (1.0ms) SELECT "items".* FROM "items" WHERE "items"."id" = $1 ORDER BY "items"."id" ASC LIMIT 1 [["id", 653]]
ProductOption Load (1.3ms) SELECT "product_options".* FROM "product_options" WHERE "product_options"."product_id" = $1 [["product_id", 28]]
Rendered admin/products/_show.html.erb (7.6ms)
Rendered admin/products/create.js.erb (9.2ms)
Completed 200 OK in 448ms (Views: 40.0ms | ActiveRecord: 27.1ms)
The the update. I doesn't work and gives an error that the nested fields are empty. It's the pp inside the update method
Started PATCH "/admin/items/653/product" for 127.0.0.1 at 2014-02-14 15:15:03 +0100
Processing by Admin::ProductsController#update as JS
Parameters: {"utf8"=>"✓", "product"=>{"item_id"=>"653", "name"=>"1", "title"=>"1", "active"=>"1", "product_options_attributes"=>{"0"=>{"name"=>"aaa", "value"=>"aaaa", "id"=>"9"}, "1"=>{"name"=>"bbb", "value"=>"bbbb"}}}, "commit"=>"Update Product", "item_id"=>"653"}
User Load (1.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = 6 ORDER BY "users"."id" ASC LIMIT 1
Item Load (0.6ms) SELECT "items".* FROM "items" WHERE "items"."id" = 653 LIMIT 1
Product Load (0.9ms) SELECT "products".* FROM "products" WHERE "products"."item_id" = $1 ORDER BY "products"."id" ASC LIMIT 1 [["item_id", 653]]
(0.6ms) BEGIN
ProductOption Load (1.3ms) SELECT "product_options".* FROM "product_options" WHERE "product_options"."product_id" = $1 AND "product_options"."id" IN (9) [["product_id", 28]]
(0.5ms) ROLLBACK
#<ActiveModel::Errors:0x007f8bdeb9f818
#base=
#<Product id: 28, item_id: 653, content: nil, active: 1, created_at: "2014-02-14 14:12:14", updated_at: "2014-02-14 14:12:14", name: "1", title: "1", ordernumber: "">,
#messages=
{:"product_options.name"=>["can't be blank"],
:"product_options.value"=>["can't be blank"]}>
Completed 200 OK in 18ms (Views: 0.1ms | ActiveRecord: 5.1ms)
I think I know what is the problem with your code. The accepts_nested_attributes_for does not require you to build any of the associated models. If the appropriate params are passed in then the model automatically builds or updates the associations.
In your case in the update method what you do is the following:
You find the relevant product. So far so good (although you could actually use a specific product id in your form)
Then you build two product options (in #set_product). This is the problem.
And in the end you update the model based on the parameters.
Now the problem with the second step is that you basically build two empty associated instances. Those are not affected by the accepts_nested_attributes. As a result you are trying to save 2+2 product options (the ones you build and the ones created by the params). Obviously you get the validation error due to the fact the two of the models have no attributes set.
You can make sure my hypothesis is correct by removing the validators from ProductOption. On update you should get 4 associated product options persisted.

How to save a serialized field

I'm trying to push values onto a serialized text field (acting as array).
In the controller I have
class DeliveriesController < ApplicationController
def new
#delivery = Delivery.new
end
def create
#user = current_user
#user.deliveries.create(params[:delivery])
#user.recent_addresses.shift if #user.recent_addresses.size >= 10
#user.recent_addresses.push(params[:delivery][:from_address])
#user.save
redirect_to root_path
end
end
User model
serialize :recent_addresses, Array
attr_accessible :recent_addresses
has_many :deliveries
The problem is that the user is not being saved with the new recent addresses. The from_address is being added within the controller but when I try save it rollsback and the recent addresses array is empty.
Parameters: {"delivery"=>{"from_address"=>"xyz"}, "commit"=>"Submit"}
SQL (0.6ms) INSERT INTO "deliveries" ("created_at", "from_address", "user_id") VALUES ($1, $2) RETURNING "id" [["created_at", Fri, 25 Oct 2013 13:21:50 UTC +00:00], ["from_address", "xyz"], ["user_id", 1]]
(0.8ms) COMMIT
(0.1ms) BEGIN
(0.2ms) ROLLBACK
Redirected to http://localhost:3000/

uuid_it : Can't mass-assign protected attributes: uuid

I used uuid_id gem to generate UUID for various models in my application(Rails 3.2.5 with Ruby 1.9.3p194). I correctly followed the steps given here
I am getting this error while creating the model tagged as uuid_it. It works fine if I remove uuid_it call from the model
Here is snapshot of the log
SQL (2.1ms) INSERT INTO "applications" ("created_at", "description", "name", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["created_at", Mon, 03 Sep 2012 10:17:59 UTC +00:00], ["description", "data mining"], ["name", "BlueBerry"], ["updated_at", Mon, 03 Sep 2012 10:17:59 UTC +00:00]]
Uuid Load (1.2ms) SELECT "uuids".* FROM "uuids" WHERE "uuids"."uuidable_id" = 5 AND "uuids"."uuidable_type" = 'Application' LIMIT 1
(0.2ms) ROLLBACK
Completed 500 Internal Server Error in 81ms
ActiveModel::MassAssignmentSecurity::Error (Can't mass-assign protected attributes: uuid):
app/controllers/applications_controller.rb:13:in `create'
where line 13 is application.create
EDIT
app/controllers/applications.rb
class ApplicationsController < ApplicationController
# some code here
def create
#application = Application.new(params[:application])
#application.creator = current_user
#application.organization = current_organization
if #application.save
redirect_to #application, notice: "Successfully created application."
else
render action: 'new'
end
end
# few lines here
end

Resources