Rails Mailer error: wrong number of arguments (1 for 0) - ruby-on-rails-3

Hello im reading Agile Web Development With Rails 4th Edition Book but im getting an error at 'Task H: Sending Mail'
I have mailer order_notifier.rb
class OrderNotifier < ActionMailer::Base
default :from => "name#email.tld"
def received
#order = order
mail(:to => order.email, :subject => 'Pragmatic Store Order Confirmation')
end
def shipped
#order = order
mail(:to => order.email, :subject => 'Pragmatic Store Order Shipped')
end
end
i have templates /views/order_notifier/ received.text.erb and shipped.text.erb like
Dear <%= #order.name %>
Thank you for your recent order from The Pragmatic Store.
You ordered the following items:
<%= render #order.line_items %>
We'll send you a separate e-mail when your order ships.
i run it from OrdersController
im not sure if use current_cart or #cart but i guess it doesnt matter
def create
#order = Order.new(params[:order])
#order.add_line_items_from_cart(current_cart)
##order.add_line_items_from_cart(#cart)
respond_to do |format|
if #order.save
Cart.destroy(session[:cart_id])
session[:cart_id] = nil
OrderNotifier.received(#order).deliver
the error im getting tels me that received method has one argument more than it needs (#order) but thats how its written in the book.. error:
ArgumentError in OrdersController#create
wrong number of arguments (1 for 0)
Where is the mistake ? Thank you.

The mistake is that your received method in the OrderNotifier does not take an argument, but your controller is passing it one. You should modify the notifier to take one argument, order.
On a side note, I do not recommend reading Agile Web Development With Rails.

Related

Delayed job and Mandrill: uninitialized constant Mandrill::API

I have mailer service where users can upload an .xls file with emails and some other user related data to send an email campaign.
I was having some timeout issues since it takes some seconds to process (as I do some validation and configuration for each email to be sent, eg: save records to database, check if an email was sent in the last 30 days, create personalised html code for each email (to create links that contain the email address as a parameter, etc).
After some research, moving this to a delayed job seemed reasonable, as suggested in this rails cast. The only problem is that I am having an error that says uninitialized constant Mandrill::API, it seems that when I run the job, the call require 'mandrill' doesn't work.
I created the task in my model file. Something like this
class Mailer < ActiveRecord::Base
attr_accessible :email, :lastname, :name
def self.send_mail(emails)
[...a lot of code here...]
require 'mandrill'
m = Mandrill::API.new ENV['MANDRILL_APIKEY']
message = {
:subject=> template.subject,
:from_name=> template.from_name,
:from_email=> from + "#" + email_domain,
:to=>mails,
:global_merge_vars=> [
{ :name => 'GREETING', :content => template.greeting},
{ :name => 'CONT1', :content => template.message},
{ :name => 'IMAGE', :content => image_url},
],
:html=>email_template,
:preserve_recipients => false,
:merge_vars => email_contents,
}
sending = m.messages.send message
end
end
from my controller I call Mailer.send_mails(emails) and it works just fine, but if I call Mailer.delay.send_mails(emails) I get the error. How can I fix this?
I have tried adding require 'mandrill' at the beginning of the class, before and after class Mailer < ActiveRecord::Base but nothing seems to work
Make sure to restart the delayed_job daemon to pick up any code changes. It does not auto-reload like the Rails development environment does.

expected Hash (got Array) for param 'samples'

I have been following Railscasts episodes of Nested forms and complex forms. During the time of creating multiple model in a single form I was able to edit, update, delete and create records for sample models that were nested in the Batch model.
I have been breaking my head from a long time and tried searching around as well but could not get any right solution for solving this problem.
my development log file gives me the following error.
ERROR MESSAGE:
Status: 500 Internal Server Error
expected Hash (got Array) for param `samples'
in my controller I have the update action like this
def update
#batch = Batch.find(params[:id])
respond_to do |format|
if #batch.update_attributes(params[:batch])
flash[:notice] = 'Successfully updated Batch.'
format.html { redirect_to(#batch) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #batch.errors, :status => :unprocessable_entity }
end
end
end
my view is something like this:
<%= form_for #batch do |f| %>
......
<%= f.fields_for :samples do |s_form| %>
.... s_form things
<% end %>
<% end %>
my model contains the same stuff :
has_many :samples, :dependent => :destroy
accepts_nested_attributes_for :samples, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
All suggestions are appreciated.
for others who met the same problem:
this error is caused when you have two fields in your form like:
video: 'some string'
video['url']: 'some url'
then rails will crash with the error: expected Hash (got String) for param
the solution is quite simple: change 'video' to something else. e.g.:
video_origin_url: 'some string'
video['url']: 'some url'
I had the same problem, and just fixed it.
Check the headers of your request. I mine I saw:
weight[2][name]:Tests
weight[2][value]:75
weight[1][name]:Quizzes
weight[1][value]:25
weight[][name]:Foo
weight[][value]:
It was the last two which caused the issue. In my case I had to give this weight an ID to get rid of the error.
I also got this error Invalid request parameters: expected Hash (got Array) for param 'cell'.
In my case, I misformed the field name like
f.text_field :name, name: 'cell[name][]'
this was causing the error. Now I did the following and the error is gone:-
f.text_field :name, name: 'cell[][name]'
in this solution I was actually trying to get data in array format.
I had this problem, when the user typed the params himself in the request like:
https://example.com/page?samples[]=1&samples[test]=2
Debugging the code, I got down to a Rack::QueryParser.parse_nested_query method in the rack gem:
# parse_nested_query expands a query string into structural types. Supported
# types are Arrays, Hashes and basic value types. It is possible to supply
# query strings with parameters of conflicting types, in this case a
# ParameterTypeError is raised. Users are encouraged to return a 400 in this
# case.
def parse_nested_query(qs, d = nil)
params = make_params
unless qs.nil? || qs.empty?
(qs || '').split(d ? (COMMON_SEP[d] || /[#{d}] */n) : DEFAULT_SEP).each do |p|
k, v = p.split('=', 2).map! { |s| unescape(s) }
normalize_params(params, k, v, param_depth_limit)
end
end
return params.to_h
rescue ArgumentError => e
raise InvalidParameterError, e.message, e.backtrace
end
From the docstring:
It is possible to supply query strings with parameters of conflicting types, in this case a ParameterTypeError is raised. Users are encouraged to return a 400 in this case.
I found few solutions here Rails ActionController::BadRequest causes 500 Server Error on production server

Rails3 ActiveResource Post Call delivers an empty Parameter Hash

I am trying to create a new "Person" in a Sinatra API app from a Rails3 app using ActiveResource and Json. In Rails3, I created a "Person" model and using ActiveResource I correctly call the API, which correctly reads the URL, but no parameters seem to get passed with the object.
From Rails3 Person Model:
class Person < ActiveResource::Base
self.site = "http://127.0.0.1:9393/"
self.collection_name = "person/add"
self.format = :json
end
From the Rails3 console:
u=Person.new({"last_name"=>"Bill", "first_name"=>"Smith"})
=> #<Person:0xb73176f0 #attributes={"last_name"=>"Bill", "first_name"=>"Smith"}, #prefix_options={}>
puts u.attributes
=> last_nameBillfirst_nameSmith
u.save
=> True
From the Sinatra app:
puts #app.params.keys
=> Nil
puts #app.params['last_name']
=> Nil
puts #app.params[:last_name]
=> Nil
Using the IRB Console this works:
Net::HTTP.post_form(URI.parse('http://127.0.0.1:9393/user/add.json'),{'first_name' => 'Smith', 'last_name' => 'Bill'})
Can someone please give some direction as to what I missed or am doing wrong thank you.
Person object should know attributes, as you did on console. When doing Person.find, it gets attrs via activeresource, but Person.new doesn't know them so that any-way to tell to Person is required at Person.new like the following:
class PeopleController < ApplicationController
...
def new
#person = Person.new(:name=>nil, :age=>nil, ...)
end
...
Does this answer?

Sending email with Rails 3 error

I am learning to how send email with Rails 3 with Agile Web Development Book, Task H. However, I keep getting the following error:
ArgumentError in OrdersController#create
wrong number of arguments (1 for 0)
Rails.root: /Applications/XAMPP/xamppfiles/htdocs/rails_projects/TUTORIALS/depot
Application Trace | Framework Trace | Full Trace
app/mailers/notifier.rb:4:in `order_received'
app/controllers/orders_controller.rb:57:in `block in create'
app/controllers/orders_controller.rb:52:in `create'
I have looked at similar discussions on gmail configuration, using setup_mail.rb here and there, but wasn't able to remove the error.
My config/environment.rb file (because i want same for dev/test/production)has my gmail details with xxxx and yyyyy:
Depot::Application.configure do
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:domain => "gmail.com",
:authentication => "plain",
:user_name => "xxxxxx#gmail.com",
:password => "yyyyyyy",
:enable_starttls_auto => true
}
end
model/notifier/order_received.text.erb has this:
Dear <%= #order.name %>
Thank you for your recent order from The Pragmatic Store.
You ordered the following items:
<%= render #order.line_items %>
We'll send you a separate e-mail when your order ships.
and finally, models/controller/orders_controller has def create method with the line Notifier:
def create
#order = Order.new(params[:order])
#order.add_line_items_from_cart(current_cart)
respond_to do |format|
if #order.save Cart.destroy(session[:cart_id])
session[:cart_id] = nil
Notifier.order_received(#order).deliver
format.html { redirect_to(store_url, :notice => 'Thank you for your order.') }
else
format.html { render :action => "new" }
format.xml { render :xml => #order.errors, :status => :unprocessable_entity }
end
end
end
I feel my email configuration was probably not done correctly, but not sure which one. Thanks!
EDIT: I managed to solve it! Instead of smtp i used sendmail.
As for the number of arguments error, the app/mailers/notifer.rb looks like this:
class Notifier < ActionMailer::Base
default :from => 'Sam Ruby <depot#example.com>'
def order_received(order)
#order = order
mail :to => order.email, :subject => 'Pragmatic Store Order Confirmation'
end
def order_shipped(order)
#order = order
mail :to => order.email, :subject => 'Pragmatic Store Order Shipped'
end
end
Although my emails and everything still works, i'm curious whether anyones know why the smtp doesn't work, and sendmail does.
You've got a space in your order_received definition:
def order_received (order)
That should be this:
def order_received(order)
Is it this line in create?
if #order.save Cart.destroy(session[:cart_id])
If that's what you really have then Ruby will try to pass whatever Cart.destroy returns to #order.save as an argument, the above is equivalent to this:
if(#order.save(Cart.destroy(session[:cart_id])))
However, the save method doesn't take any arguments so you get a "wrong number of arguments (1 for 0) in OrdersController#create" error message. I'd guess that you mean:
if #order.save
Cart.destroy(session[:cart_id])
# etc.

Rails 3 ActionMailer and Wicked_PDF

I'm trying to generate emails with rendered PDF attachements using ActionMailer and wicked_pdf.
On my site, I'm using already both wicked_pdf and actionmailer separately. I can use wicked_pdf to serve up a pdf in the web app, and can use ActionMailer to send mail, but I'm having trouble attaching rendered pdf content to an ActionMailer (edited for content):
class UserMailer < ActionMailer::Base
default :from => "webadmin#mydomain.com"
def generate_pdf(invoice)
render :pdf => "test.pdf",
:template => 'invoices/show.pdf.erb',
:layout => 'pdf.html'
end
def email_invoice(invoice)
#invoice = invoice
attachments["invoice.pdf"] = {:mime_type => 'application/pdf',
:encoding => 'Base64',
:content => generate_pdf(#invoice)}
mail :subject => "Your Invoice", :to => invoice.customer.email
end
end
Using Railscasts 206 (Action Mailer in Rails 3) as a guide, I can send email with my desired rich content, only if I don't try to add my rendered attachment.
If I try to add the attachment (as shown above), I get an attachement of what looks to be the right size, only the name of the attachment doesn't come across as expected, nor is it readable as a pdf. In addition to that, the content of my email is missing...
Does anyone have any experience using ActionMailer while rendering the PDF on the fly in Rails 3.0?
Thanks in advance!
--Dan
WickedPDF can render to a file just fine to attach to an email or save to the filesystem.
Your method above won't work for you because generate_pdf is a method on the mailer, that returns a mail object (not the PDF you wanted)
Also, there is a bug in ActionMailer that causes the message to be malformed if you try to call render in the method itself
http://chopmode.wordpress.com/2011/03/25/render_to_string-causes-subsequent-mail-rendering-to-fail/
https://rails.lighthouseapp.com/projects/8994/tickets/6623-render_to_string-in-mailer-causes-subsequent-render-to-fail
There are 2 ways you can make this work,
The first is to use the hack described in the first article above:
def email_invoice(invoice)
#invoice = invoice
attachments["invoice.pdf"] = WickedPdf.new.pdf_from_string(
render_to_string(:pdf => "invoice",:template => 'documents/show.pdf.erb')
)
self.instance_variable_set(:#lookup_context, nil)
mail :subject => "Your Invoice", :to => invoice.customer.email
end
Or, you can set the attachment in a block like so:
def email_invoice(invoice)
#invoice = invoice
mail(:subject => 'Your Invoice', :to => invoice.customer.email) do |format|
format.text
format.pdf do
attachments['invoice.pdf'] = WickedPdf.new.pdf_from_string(
render_to_string(:pdf => "invoice",:template => 'documents/show.pdf.erb')
)
end
end
end
I used of Unixmonkey's solutions above, but then when I upgraded to rails 3.1.rc4 setting the #lookup_context instance variable no longer worked. Perhaps there's another way to achieve the same clearing of the lookup context, but for now, setting the attachment in the mail block works fine like so:
def results_email(participant, program)
mail(:to => participant.email,
:subject => "my subject") do |format|
format.text
format.html
format.pdf do
attachments['trust_quotient_results.pdf'] = WickedPdf.new.pdf_from_string(
render_to_string :pdf => "results",
:template => '/test_sessions/results.pdf.erb',
:layout => 'pdf.html')
end
end
end
Heres' how I fixed this issue:
Removed wicked_pdf
Installed prawn (https://github.com/sandal/prawn/wiki/Using-Prawn-in-Rails)
While Prawn is/was a bit more cumbersome in laying out a document, it can easily sling around mail attachments...
Better to use PDFKit, for example:
class ReportMailer < ApplicationMailer
def report(users:, amounts:)
#users = users
#amounts = amounts
attachments["proveedores.pdf"] = PDFKit.new(
render_to_string(
pdf: 'bcra',
template: 'reports/users.html.haml',
layout: false,
locals: { users: #users }
)
).to_pdf
mail subject: "Report - #{Date.today}"
end
end