Problems sending email from post data using ActionMailer - ruby-on-rails

I'm currently using Rails 3 and working on a contact form. My data is being sent and I can access it from the params hash but I am being thrown strange errors when I try to send it to my ActionMailer class to be used in an email.
It's currently throwing this error.
undefined method `TestName' for #<MessageMailer:0x00000003f43af0>
and says the error is on these lines
app/mailers/message_mailer.rb:8:in `message'
app/controllers/contact_controller.rb:20:in `message'
The strange thing is that 'TestName' is the value I have entered into the contact form for the :name input.
Here is my code from message_mailer.rb and contact_controller.rb
MessageMailer
class MessageMailer < ActionMailer::Base
include ActiveModel::Validations
def message(data)
#data = data
validates_presence_of #data[:name]
validates_presence_of #data[:email]
validates_presence_of #data[:website]
validates_presence_of #data[:message]
mail(:from => "email#domain.com", :to => "email#domain.com", :subject => "New Message From #{data.name}")
end
end
ContactController
class ContactController < ApplicationController
def message
if request.post?
#data = {
:name => params[:name],
:email => params[:email],
:website => params[:website],
:message => params[:message]
}
if MessageMailer.message(#data).deliver
redirect('/contact', :flash => 'Thank you for the message. I will get back to you as soon as possible')
else
redirect('/contact', :flash => 'Oops! Something went wrong. I will look into it. Until it\'s fixed you can email me at email#domain.com')
end
else
redirect('/contact', :flash => 'Please fill out the contact form to get in touch.')
end
end
end
It is saying the errors are on the line validates_presence_of #data[:name] in message_mailer.rb and if MessageMailer.message(#data).deliver in contact_controller.rb
Any help would be great!
UPDATE: Alright, I solved the original error but now it is throwing this error wrong number of arguments (0 for 1) on MessageMailer.message(#data).deliver. I have tried changing #data to params to bypass any issues with the #data variable and it is still giving it.

validates_presence_of (and other validation methods) are designed to be class methods that take a property name to test for. So the way you are using them (which is incorrect inside a method) causes it to evaluate to
validates_presence_of TestName
which really results in it checking for
self.TestName
which is why you get the undefined method error.
Ways to fix it...
Don't use validations like that in mailer. Just manually check for emptiness of those strings using String#empty?
Create a separate object to which the #data values get assigned. Use validates_presence_of declarations (at the class level like ActiveRecord) and test using #validate!
HTH

Please follow http://railscasts.com/episodes/206-action-mailer-in-rails-3 and
http://guides.rubyonrails.org/action_mailer_basics.html .
There you might have made mistake in POST data MessageMailer.message(#data) may be class name & function name problem.
Or may be due to you need to restart server after mail configuration setup.
let me know if it is not solved?

Related

Validating Virtual Attributes In Forms : undefined method `valid?' for :name:Symbol

I have two fields in a form I would like to validate the presence of, before sending. The problem though is that the controller's model doesn't have these fields in the database, so I tried making virtual attributes. I'm not quite sure how to get it to work though.
I tried doing this in the Model, called "Find_number"
class FindNumber < ActiveRecord::Base
attr_accessor :name
attr_accessor :original_number
validates :name, presence: true
validates :original_number, presence: true
end
and the following in the create action of the Find_numbers controller
def create
#user = current_user
client = Twilio::REST::Client.new(#user.twilio_account_sid, #user.twilio_auth_token)
search_params = {}
%w[in_postal_code near_number contains].each do |p|
search_params[p] = params[p] unless params[p].nil? || params[p].empty?
end
local_numbers = client.account.available_phone_numbers.get('US').local
#numbers = local_numbers.list(search_params)
if :name.valid? && :original_number.errors.any?
unless #numbers.empty?
render 'find_numbers/show'
else
flash.now[:error] = "Sorry, We Couldn't Find Any Numbers That Matched Your Search! Maybe Something Simpler?"
render 'find_numbers/new'
end
else
flash.now[:error] = "Sorry, We Couldn't Find Any Numbers That Matched Your Search! Maybe Something Simpler?"
render 'find_numbers/new'
end
end
When I enter info though, I get the error
undefined method `valid?' for :name:Symbol
I'm probably calling the :name and :original_number attributes incorrectly, and the double if then statements look very newbish :P.
What would I need to replace if :name.valid? && :original_number.errors.any? , to make sure that it validates? Or is there a lot more I'm missing?
I think you are confusing the boundary between 'controller' and 'model'. The controller doesn't know anything about the validations inside of the model that you've written. The fact that the controller is called FindNumbersController and the model is called FindNumber doesn't really mean anything in terms of shared functionality.
You would need to explicitly create an instance of the model with the passed in params, and let the model perform the validation on the instance
find_number = FindNumber.new(params.slice(:name, :original_number))
Then you can ask whether the instance as a whole is valid
find_number.valid?
or whether a specific field has any error messages
find_number.errors[:field].any?
So, :name.valid? becomes find_number.errors[:name].empty? and :original_number.errors.any? becomes find_number.errors[:original_number].any?

Rails - Allowing for calling in Model Validation in a Controller

I have the following in my user.rb model:
INVALID_EMAILS = %w(gmail.com hotmail.com)
validates_format_of :email, :without => /#{INVALID_EMAILS.map{|a| Regexp.quote(a)}.join('|')}/, :message => "That email domain won't do.", :on => :create
For various reasons, I want to be able to use this logic in my controller to check an email's input before it is user.created, which is when the above normall runs.
How can I turn the above into a method that I can call in controllers other than user? Possible?
And if is called and returned false I then want to do errors.add so I can let the user know why?
Thanks
Trying:
def validate_email_domain(emailAddy)
INVALID_EMAILS = %w(gmail.com googlemail.com yahoo.com ymail.com rocketmail.com hotmail.com facebook.com)
reg = Regexp.new '/#{INVALID_EMAILS.map{|a| Regexp.quote(a)}.join('|')}/'
self.errors.add('rox', 'Hey, Ruby rox. You have to say it !') unless reg.match attribute
end
Update:
..
Rails.logger.info validate_email_domain(email)
...
def valid_email_domain(emailAddy)
reg = Regexp.new '/#{User::INVALID_EMAILS.map{|a| Regexp.quote(a)}.join("|")}/'
return true if emailAddy.scan(reg).size == 0
end
You cannot assign a constant inside a method, because that would make it "dynamic constant assignment". Instead, define this constant in your model class and then reference it in your controller by using User::INVALID_EMAILS
Okay, if I understand you.
You want to do something like below:
u = User.new
u.email = "jsmith#gmail.com"
if !u.valid?
puts u.errors.to_xml
//do something
return
end
What you do with those errors is going to come down to how you want those reported back, usually I just shoot them back as xml into a flash[:error], which is the normal default behavior if you're doing scaffolds. The puts is there so you can see how to access the errors.
Additional
As a rule try to avoid duplicating validation logic. Rails provides everything you need for validating without creating different methods in different places to accomplish the same thing.

Rails: Delayed Job --> Not picking up 'from' field when sending asynchronous mail

I'm running 2.1.1, Rails 3, and having a heckuva time getting the delayed_job gem working. If I strip out handle_asynchronously on a mailer, everything works fine...but if I put it back in, I get:
undefined method `name' for nil:NilClass (where 'name' comes from #contact.name ...which works fine when handle_asynchronously is disabled).
If I strip out all the #contact template info, I get:
"A sender (Return-Path, Sender or From) required to send a message"?
Is this me doing something wrong or some sorta bug? Relevant code below (my#email.here replaced with legit email address)
class ContactMailer < ActionMailer::Base
default :from => "my#email.here"
def contact_mail(contact)
#contact = contact
mail(:to => ENV['MANAGER_EMAIL'], :subject => 'Delayed Job Test', :from => 'my#email.here', :content_type => 'text/plain')
end
handle_asynchronously :contact_mail, :run_at => Proc.new { 2.seconds.from_now }
end
Any suggestions very appreciated.
Try calling the method with the actual email address:
def contact_mail(contact_email)
mail(:to => ENV['MANAGER_EMAIL'], :subject => 'Delayed Job Test', :from => contact_email, :content_type => 'text/plain')
end
That's the only thing I can think of which might help without seeing your actual code. Your error says you're calling name on a nil object, but I can't see anywhere where you're calling .name...
I had the same problem and solved it by removing this line:
default :from => "my#email.here"
But I don't know why it crashed with this line..
Rails 3 Mailers
Due to how mailers are implemented in Rails 3, we had to do a little work around to get delayed_job to work.
# without delayed_job
Notifier.signup(#user).deliver
# with delayed_job
Notifier.delay.signup(#user)
Remove the .deliver method to make it work. It’s not ideal, but it’s the best we could do for now
https://github.com/collectiveidea/delayed_job#rails-3-mailers

ActiveRecord custom validation problem

I'm having a problem with validation in my RoR Model:
def save
self.accessed = Time.now.to_s
self.modified = accessed
validate_username
super
end
def validate_username
if User.find(:first, :select => :id, :conditions => ["userid = '#{self.userid}'"])
self.errors.add(:userid, "already exists")
end
end
As you can see, I've replaced the Model's save method with my own, calling validate_username before I call the parent .save method. My Problem is, that, even though the error is being added, Rails still tries to insert the new row into the database, even if the user name is a duplicate. What am I doing wrong here?
PS: I'm not using validate_uniqueness_of because of the following issue with case sensitivity: https://rails.lighthouseapp.com/projects/8994/tickets/2503-validates_uniqueness_of-is-horribly-inefficient-in-mysql
Update: I tried weppos solution, and it works, but not quite as I'd like it to. Now, the field gets marked as incorrect, but only if all other fields are correct. What I mean is, if I enter a wrong E-Mail address for example, the email field is marked es faulty, the userid field is not. When I submit a correct email address then, the userid fields gets marked as incorrect. Hope you guys understand what I mean :D
Update2: The data should be validated in a way, that it should not be possible to insert duplicate user ids into the database, case insensitive. The user ids have the format "user-domain", eg. "test-something.net". Unfortunately, validates_uniqueness_of :userid does not work, it tries to insert "test-something.net" into the database even though there already is an "Test-something.net". validate_username was supposed to be my (quick) workaround for this problem, but it didn't work. weppos solution did work, but not quite as I want it to (as explained in my first update).
Haven't figured this out yet... anyone?
Best regards,
x3ro
Why don't you use a callback and leave the save method untouched?
Also, avoid direct SQL value interpolation.
class ... < ActiveRecord::Base
before_save :set_defaults
before_create :validate_username
protected
def set_defaults
self.accessed = Time.now.to_s
self.modified = accessed
end
def validate_username
errors.add(:userid, "already exists") if User.exists?(:userid => self.userid)
errors.empty?
end
end
How about calling super only if validate_username returns true or something similar?
def save
self.accessed = Time.now.to_s
self.modified = accessed
super if validate_username
end
def validate_username
if User.find(:first, :select => :id, :conditions => ["userid = '#{self.userid}'"])
self.errors.add(:userid, "already exists")
return false
end
end
... I think that you could also remove totally the super call. Not sure, but you could test it out.

Rails form validation

I have a Rails app that lets a user construct a database query by filling out an extensive form. I wondered the best practice for checking form parameters in Rails. Previously, I have had my results method (the one to which the form submits) do the following:
if params[:name] && !params[:name].blank?
#name = params[:name]
else
flash[:error] = 'You must give a name'
redirect_to :action => 'index'
return
end
But for several form fields, seeing this repeated for each one got tiresome. I couldn't just stick them all in some loop to check for each field, because the fields are set up differently:
a single key: params[:name]
a key and a sub-key: params[:image][:font_size]
only expect some form fields to be filled out if another field was set
Etc. This was also repetitive, because I was setting flash[:error] for each missing/invalid parameter, and redirecting to the same URL for each one. I switched to using a before_filter that checks for all necessary form parameters and only returns true if everything's okay. Then the my results method continues, and variables are just assigned flat-out, with no checking involved:
#name = params[:name]
In my validate_form method, I have sections of code like the following:
if (
params[:analysis_type][:to_s] == 'development' ||
params[:results_to_generate].include?('graph')
)
{:graph_type => :to_s, :graph_width => :to_s,
:theme => :to_s}.each do |key, sub_key|
unless params[key] && params[key][sub_key]
flash[:error] = "Cannot leave '#{Inflector.humanize(key)}' blank"
redirect_to(url)
return false
end
end
end
I was just wondering if I'm going about this in the best way, or if I'm missing something obvious when it comes to parameter validation. I worry this is still not the most efficient technique, because I have several blocks where I assign a value to flash[:error], then redirect to the same URL, then return false.
Edit to clarify: The reason I don't have this validation in model(s) currently is for two reasons:
I'm not trying to gather data from the user in order to create or update a row in the database. None of the data the user submits is saved after they log out. It's all used right when they submit it to search the database and generate some stuff.
The query form takes in data pertaining to several models, and it takes in other data that doesn't pertain to a model at all. E.g. graph type and theme as shown above do not connect to any model, they just convey information about how the user wants to display his results.
Edit to show improved technique: I make use of application-specific exceptions now, thanks to Jamis Buck's Raising the Right Exception article. For example:
def results
if params[:name] && !params[:name].blank?
#name = params[:name]
else
raise MyApp::MissingFieldError
end
if params[:age] && !params[:age].blank? && params[:age].numeric?
#age = params[:age].to_i
else
raise MyApp::MissingFieldError
end
rescue MyApp::MissingFieldError => err
flash[:error] = "Invalid form submission: #{err.clean_message}"
redirect_to :action => 'index'
end
You could try active_form (http://github.com/cs/active_form/tree/master/lib/active_form.rb) - just ActiveRecord minus the database stuff. This way you can use all of AR's validation stuff and treat your form like you would any other model.
class MyForm < ActiveForm
validates_presence_of :name
validates_presence_of :graph_size, :if => # ...blah blah
end
form = MyForm.new(params[:form])
form.validate
form.errors
Looks like you are doing the validation in the controller, try putting it in the model, it's better suited to that sort of thing.
If you were to tackle the problem again today, you could create a model for the query parameter set and use Rails' built in validations, Rails 3 makes this a lot easier with ActiveModel::Validations see this post.
Model
class Person
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :name
attr_accessor :email
validates_presence_of :name,:message => "Please Provide User Name"
validates_presence_of :email,:message => "Please Provide Email"
end
Note that you don't necessarily need to save/persist the model to validate.
Controller
#person.name= params["name"]
#person.email= params["email"]
#person.valid?
One you called .valid? method on the model, the errors will be populated inside #person object. Hence,
View
<%if #person.errors.any? %>
<%#person.errors.messages.each do|msg| %>
<div class="alert alert-danger">
<%=msg[0][1]%>
</div>
<%end%>
<%end%>

Resources