Manually Send Email Rails - ruby-on-rails

I've been trying to implement the code from this question: Send an email manually of a specific page in rails app
The only difference is that I need to fetch the email address from my model. This is usually no problem when sending emails from models.
UserMailer.report(self).deliver
But I want to click on a button in the show view of my record.
I need to manually send out emails using the details of the record in the email.
Maybe there is a better approach than using an extra controller for this?
# app/mailers/user_mailer.rb
class UserMailer < ActionMailer
def report(thing)
#thing = thing
mail :to => thing.email, :from => 'you#example.com',
:subject => 'that report you want'
end
end
# app/views/user_mailer/report.html.erb
<h1>Report</h1>
<p>Here is your <% #thing.customer_id %></p>
# app/controllers/reports_controller.rb
def create
UserMailer.report(#thing).deliver
flash[:notice] = 'report sent!'
redirect_to root_path # or wherever
end
# in a view
<% form_tag(reports_path(#thing), :method => :post) do %>
<% submit_tag 'send report email' %>
<% end %>
I'm returning null with the code above:
ArgumentError (wrong number of arguments (0 for 1)):
app/controllers/reports_controller.rb:3:in `create'

Create is a post request in rails, you cannot pass parameter like this you need to fetch from params. I'm seeing you are giving it a parameter which is wrong.
Secondly you are doing #thing = thing and then you are sending thing (without #) to report method of UserMailer which is also wrong, it would be be nil in report method. you should do UserMailer.report(#thing).deliver after #thing is an object which has email

Related

Send devise confirmation email manually later

I have added devise :confirmable to my model and created a before_create to skip the confirmation.
before_create :skip_confirmation
def skip_confirmation
self.skip_confirmation!
end
I have a mailer named store_mailer.rb along with appropriate views app/views/stores/mailer/confirmation_instroctions.html.erb to send out the confirmation email.
class StoreMailer < Devise::Mailer
helper :application # gives access to all helpers defined within `application_helper`.
include Devise::Controllers::UrlHelpers # Optional. eg. `confirmation_url`
default template_path: 'store/mailer' # to make sure that your mailer uses the devise views
end
confirmation_instroctions.html.erb
<h2>Resend confirmation instructions</h2>
<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email) %>
</div>
<div class="actions">
<%= f.submit "Resend confirmation instructions" %>
</div>
<% end %>
<%= render "stores/shared/links" %>
I'm trying to send the confirmation email with this:
StoreMailer.confirmation_instructions(#store).deliver
But it returns the following error: ArgumentError in TransactionsController#create
wrong number of arguments (given 1, expected 2..3)
Any ideas what might be wrong?
Update 1
transaction_controlller.rb
def create
nonce_from_the_client = params['payment_method_nonce']
#result = Braintree::Customer.create(
first_name: params['first_name'],
last_name: params['last_name'],
:payment_method_nonce => nonce_from_the_client
)
if #result.success?
puts #result.customer.id
puts #result.customer.payment_methods[0].token
StoreMailer.confirmation_instructions(#store).deliver
redirect_to showcase_index_path, notice: 'Subscribed, please check your inbox for confirmation'
else
redirect_back( fallback_location: (request.referer || root_path),
notice: "Something went wrong while processing your transaction. Please try again!")
end
end
#store.send_confirmation_instructions.deliver
This generates the confirmation token, as well as sends the mail.
From the title seems like you are trying to manually send the email later. The proposed solution in your question is just postponing the email, not exactly manually triggering it.
If you want to forbid sending the email immediately and then to send it manually you could do it like this:
class RegistrationsController
...
def create
...
resource.skip_confirmation_notification!
...
end
Some other place where you want to trigger the email, call:
User.first.send_confirmation_instructions
User.first - change with your user
confirmation_instructions is a method defined in Devise::Mailer (the superclass of your StoreMailer class).
As you can see here and here, it accepts 2 mandatory arguments and 1 optional.
You're invoking the method passing just one argument.
You must pass the second argument (token) too, like the following:
def create
# ...
# Note: I'm not sure this is the token you really need.
# It's your responsibility check if it's correct.
token = #result.customer.payment_methods.first.token
StoreMailer.confirmation_instructions(#store, token).deliver
# ...
end

My invoice link returns nill

When the user clicks on 'send invoice', the invoice show link is sent to the client's email. However, I get this error each time I click on send
"undefined method `id' for nil:NilClass"
Email message view
<h3>Hi <%= #client.try(:first_name) %></h3>
<p>Click the link below to view invoice</p>
<%= link_to 'INVOICE', edit_invoice_url(#invoice.id) %>
User mailer controller
def show
#user=current_user
#client=Client.find_by(params[:client_id])
#invoice = #client.invoices.find_by(id: params[:id])
end
def update
#user=User.find_by(params[:user_id])
#client = Client.find_by(params[:client_id])
#invoice = Invoice.find_by(params[:qty])
if #invoice
UserMailer.invoice_mail(#client).deliver
flash[:change_pass] = "Invoice sent successfully!"
redirect_to client_path(#user.company_name)
end
end
Send invoice link
<%= link_to 'send', invoice_path(#invoice), method: :patch %>
Maybe it's because find_by finder require an attribute for right SQL query.
And if you want to find instance by id - you have to use find method.
For example:
> Box.find_by(3)
=> Box Load (3.1ms) SELECT "boxes".* FROM "boxes" WHERE (3) LIMIT 1
PG::DatatypeMismatch: ERROR: argument of WHERE must be type boolean, not type integer
and Box.find_by(id: 3) will return an object (if exist) like Box.find(3)

Ruby on Rails, find if a certain value exists in a column

I'm building a website with user authentication. And I just noticed that if I create a user with an existing email, it just doesn't work which is normal, but I'd like to give feedback to the user. So for that I need to determine if any user has already that email.
I've tried some things like:
if User.email.include? params[:user][:email]
flash.now[:error] = "A user with this password already exists"
render :action => :new, :layout => 'signin-layout.html.erb'
Those are the columns for User:
2.1.0 :014 > User.column_names
=> ["id", "name", "email", "created_at", "updated_at", "password_digest", "remember_token", "admin", "team_id", "teamLeader"]
And the result I get is a big fat error:
undefined method `email' for #<Class:0x00000102b9a908>
So if anybody sees what I'm doing wrong, or knows another way to do it, that would be great.
Cheers
Try this:
if User.exists?(:email => params[:user][:email])
flash.now[:error] = "A user with this password already exists"
render :action => :new, :layout => 'signin-layout.html.erb'
...
else
# more code here..
end
Also, you can add validations when you're creating the object:
class User
validates_uniqueness_of :email
More on different validations here: http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html
I believe this way of doing the validation is wrong, you should validate the uniqueness of the email in the User model itself like below
validates :email, uniqueness: true #User model
This way the validation would be on the the User model. The problem with the condition you are using is that it is accessing an instance method specific to objects as a class method. So User.email means that there is a method called email that has the same logic for all the instances of the user class or more formally a class method which you don't have here. The email is an attribute specific to each user an instance attribute/variable (Each user has a different email).
You can see/show the validation errors present on the model using #user.errors.full_messages where #user is the instance you are trying to register/save.
This is how I would normally do it if this action is for registering users i.e. creating new users.
class User < ActiveRecord::Base
#attribute accessors and accessible
validates :email, uniqueness: true
end
class UsersController < ApplicationController
def create
#user = User.new params[:user]
if #user.save
#code for redirect or rendering the page you want
else
render 'new'
end
end
end
#new.html.erb
<%= form_for #user do |f| %>
<% if #user.errors.any? %>
<div>
<ul>
<% #job.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
#form fields
<% end %>
This way you display all the error messages to the user at the top of the registration form.

Ruby on Rails: Send email from show page

I am a Rails noob and have a problem sending an email from a show page. There are several contact form tutorials out there but I cannot find one where I send an email from a page like a 'show' page. I have big errors in my routes I believe. In the model I state that Users have several Promotions and on the promotions show page I want to allow the current_user to send an email to #user.
here is app/mailers/quote_mailer.rb
class QuoteMailer < ActionMailer::Base
default :from => "tim#example.com"
def quote_mail(promotion)
#user = user
mail(:to => user.email, :subject => "You have an inquiry homeboy!")
end
end
In promotions_controller I put this action which I think might be wrong:
def quotedeliver
QuoteMailer.quote_mail.deliver
flash[:notice] = 'report sent!'
redirect_to root_path # or wherever
end
Here is the form that I use to send the email (the :url is probably wrong but I dont know how it should look)
<%= form_for quote_mail, :url => quotedeliver_promotion_path(promotion), :html => {:method => :put } do |f| %>
<%= f.text_area :body %>
<%= f.submit %>
<% end %>
I would love some help with this. I cannot find anything like it on stackoverflow, I have been trying for days. Thank you!
You are probably missing the route in config/routes.rb
you can define it like
post '/quotedeliver_promotion' => 'promotions#quotedeliver', :as => quotedeliver_promotion
Note that quotedeliver has to be rewritten quote_deliver to follow ruby syntax conventions. When you call
QuoteMailer.quote_mail.deliver
You are not giving the parameter, so try this
QuoteMailer.quote_mail(current_user).deliver
And change your method with
def quote_mail(user)
mail ....
end
and you are all good
There are some excellent screen casts (through Railscasts) regarding sending e-mail http://railscasts.com/?tag_id=28.
One last thing, do not attach your mail sending method to a show action (if you are doing currently), the reason is show action is only for view something and users might be refreshing that page, So if you attach a mailer to that, mails might go out for each refresh.
def quote_mail(promotion)
#user = user
mail(:to => user.email, :subject => "You have an inquiry homeboy!")
end
from where you are access user variable, it should be promotion i think.

Validation messages after redirect

We have a form to submit ratings for a certain restaurant in a in our views/restaurants/show.html.erb. If there is a validation error we get redirected back to views/restaurants/show.html.erb but the validation messages do not appear. We figured out that this happens because we lose the messages using redirect_to(#restaurant) in our RatingController create action. But how can we get back without redirection?
Thanks!
Here is how I solved this. (Note that in what follows I'm obviously just including just the most relevant lines.)
In the model there may be multiple validations and even methods that potentially report on multiple errors.
class Order < ActiveRecord::Base
validates :name, :phone, :email, :presence => true
def some_method(arg)
errors.add(:base, "An error message.")
errors.add(:base, "Another error message.")
end
end
As well, the controller action may set flash messages. Finally, the user may have entered data into the input fields, and we want it to persist through the redirect_to too.
class OrdersController < ApplicationController
def create
#order = Order.new(params[:order])
respond_to do |format|
if #order.save
session.delete(:order) # Since it has just been saved.
else
session[:order] = params[:order] # Persisting the order data.
flash[:notice] = "Woohoo notice!" # You may have a few flash messages
flash[:alert] = "Woohoo alert!" # as long as they are unique,
flash[:foobar] = "Woohoo foobar!" # since flash works like a hash.
flash[:error] = #order.errors.to_a # <-- note this line
format.html { redirect_to some_path }
end
end
end
end
Depending on your setup, you may or may not need to save the model data, such as order, to the session. I did this for the purpose of passing the data back to the original controller, and thereby being able to setup the order there again.
In any case, to display the actual error and flash messages, I did the following (in views/shared/_flash_messages.html.erb, but you could do it in application.html.erb or wherever else makes sense for your app). And this is thanks to that line flash[:error] = #order.errors.to_a
<div id="flash_messages">
<% flash.each do |key, value|
# examples of value:
# Woohoo notice!
# ["The server is on fire."]
# ["An error message.", "Another error message."]
# ["Name can't be blank", "Phone can't be blank", "Email can't be blank"]
if value.class == String # regular flash notices, alerts, etc. will be strings
value = [value]
end
value.each do |value| %>
<%= content_tag(:p, value, :class => "flash #{key}") unless value.empty? %>
<% end %>
<% end %>
</div><!-- flash_messages -->
To be clear, regular flash messages such as notices, alerts, etc. will be strings, however errors will be arrays since the above call was errors.to_a
You can pass your error on flash message
flash[:error] = #restaurant.errors
After you need display it in your redirect
Here is how I did it still doing the redirect:
Just before you redirect on validation errors in your controller store errors to flash like suggested by #shingara:
if #restaurant_rating.save
redirect_to #restaurant, :notice => "Successfully added rating to restaurant."
else
flash[:error] = #restaurant_rating.errors
redirect_to #restaurant, :alert => "There were errors to add rating to restaurant. "
end
Then in your form for rating you assign errors back for the rating object just before rendering the form:
- flash[:error].messages.each {|error| #restaurant_rating.errors.add(error[0], error[1][0]) } if flash[:error]
= simple_form_for #restaurant_rating do |f|
....
You can use render instead of redirect_to
render :action => "show"
or set flash[:error], flash[:notice] again, because they automatically reseted
After your clarification in the comment, you need to setup your
/app/views/layouts/application.html.erb
with this line
<%- flash.each do |name, msg| -%><%= content_tag :div, msg, :id => "flash_#{name}" %><%- end -%>

Resources