Ruby on Rails: Send email from show page - ruby-on-rails

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.

Related

Manually Send Email 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

Destroying model which matches input

So I have an email field in a model.
I would like a path in this model, where a field shows up in the view, and when I type an email address, and that address matches an existing model, it gets deleted. For unsubscribing from newsletter.
something like this:
newsletter_controller.rb
def unsubscribe(email)
#newsletter = Newsletter.where(:email => email)
#newsletter.destroy
end
in the view:
simple_form_for #newsletter do |f|
f.input :email, method: delete
end
I got no idea how the view should work in the Rails Way.
In config/routes.rb, I suppose you have resources :newsletters
Add a route for unsubscribe as following:
resources :newsletters do
post 'unsubscribe', :on => :member
end
Check rake routes, you should have obtained a route path as unsubscribe_newsletter_path with POST verb.
Now, in your view:
=form_for(:newsletter, :url => unsubscribe_newsletter_path) do |f|
=f.label :email
=f.text_field :email
=f.submit "Unsubscribe"
(Change it as per syntax of simple_form)
Now, in newsletter_controller.rb(it should have been newsletter*s*_controller), add the method as:
def unsubscribe
#newsletter = Newsletter.where(:email => params[:newsletter][:email])
#newsletter.destroy if #newsletter
redirect_to root_path
end
I hope it helps. Comment with places where it gives you error or doesn't work. I'll try to help.
Good luck. :)

RESTful way of updating a model from different view

My application has a User model.
In the home#index view, I present a form for the current User to update their email address, using form_for.
Now if my application is to remain RESTful, as I understand it the Haml in app/views/home/index.html.haml should look something like:
- form_for current_user, :url => { :action => "update", :controller => "user" } do |f|
= f.text_field :email
= f.submit "Update email address"
My question is as follows: what is the correct way to get the User model to redirect to the home#index view after the update?
You can give redirect to your format.html on your controller def update, like
format.html { redirect to :back }
this will redirect to the page that send request before.
That's the simplest way..!
In this case I actually reverted to using resourceful routes... far cleaner.
Thanks for the other suggestions.

Redmine: Custom filter field for adding News

I'd like to add a custom filter field to "Add News" page in Redmine,
so that when I add a new news I could select group of users the email should be sent to.
The field itself is a list of Redmine User groups and every user is assigned to at least 1 of them.
Has anybody done this? Any suggestions would be appreciated
I've located the 3 files related to the issue:
/app/controller/news_controller.rb
/app/models/news.rb
/app/views/news/_form.html.erb
Environment:
Redmine version 2.2.1.stable.11156
Ruby version 1.8.7 (x86_64-linux)
Rails version 3.2.11
Environment production
Database adapter MySQL
Redmine plugins:
no plugin installed
So far I've done only 1 modification in Redmine, which sends added news to all registered users.
File: /app/modelsmailer.rb
Overview:
EDIT: Following your advice I moved mailer function to the controller:
def create
#news = News.new(:project => #project, :author => User.current)
#news.safe_attributes = params[:news]
#news.save_attachments(params[:attachments])
if #news.save
#news_added(#news)
if params[:group]
mail :to => GroupsUser.find(params[:group][:ids]).joins(:users).select("users.mail").compact,
:subject => "[#{#news.project.name}] #{l(:label_news)}: #{#news.title}"
else
render :new
end
end
end
But I'm getting error: NameError (uninitialized constant NewsController::GroupsUser): pointing to line
mail :to => GroupsUser.find
news_controller.rb:
def new
#news = News.new
#groups = GroupsUser.all
end
news/_form.html.erb:
<%= label_tag :group_ids "Groups"
<%= collection_select :group, :ids, #groups, :id, :name, {}, multiple: true %>
Edit:
I'm going to have to take a few guesses on what your controllers look like, but I'll give you something close. Based on the mailer function you provided, I'm assuming that was called out of the create controller after the News was saved. I would call the mail function after that. Something like this:
def create
news = News.new(params[:news]
if news.save
news_added(news)
send_mail_to_groups(params[:group][:ids]) if params[:group]
redirect_to ...
else
render :new
end
end
The mailing part should be removed from news_added
def news_added(news)
redmine_headers 'Project' => news.project.identifier
#author = news.author
message_id news
#news = news
#news_url = url_for(:controller => 'news', :action => 'show', :id => news)
end
in favor of its own new routine:
send_mail_to_users_by_group_ids(group_ids)
# Woo: Sent to all users, despite their email settings
mail :to => GroupsUser.find(group_ids).joins(:users).select("users.mail").compact,
:subject => "[#{#news.project.name}] #{l(:label_news)}: #{#news.title}"
end
You might want to add a where clause to only include active users.
I think that's about right. I'm doing it off the top of my head so there's probably a typo or error or two in there. Hopefully it points you in the right direction though.

Preserving form submission through log in / sign up in Rails

Say I have a site like this (generic Q&A site) in Rails and I wanted this "ask" page w/ a text box to be the first page a user sees, even if he's not logged in. He enters a question, and on the 'new' method I check that he's not logged in, and bounced him to /session/new, where he can either log in or create a new account. Question is, how do I (and what is the best way to) preserve that question that he initially asked all through this process?
I'm understanding the flow of action described in the question to be
user is presented with a form
user is redirected to log in page on submit
user is redirected back to form on successful log in
repopulate form on load (Question asks how to do this step)
user finally submits their form.
With steps 2-4 omitted if the user is logged in.
I'm sorry, but I see your question more as a symptom of an underlying UI issue than a rails question.
If only logged in users can post questions, then why display the text box?
If a user is going to have log in any way, why not get that out of the way first. An even better solution is to integrate the log in and form.
Something like this in the view:
<% form_for :question do |form| %>
<% unless logged_in? %>
<% fields_for :session do |session_form|%>
<%= session_form.label :login %>
<%= session_form.text_field :login %>
<%= session_form.label :password %>
<%= session_form.password_field :password %>
<%end%>
<%end%>
<%= form.text_area :question %>
<%end%>
And in the controller
def new
...
unless params[:session].nil?
self.current_user = User.authenticate(params[:session][:login], params[:session][:password])
end
if logged_in?
flash[:notice] = "Logged in successfully"
else
flash[:error] = "Incorrect username and or password."
end
if logged_in? && #question.save
.... process successful entry
else
... process unsuccessful entry
end
end
Edit: Mohamad's raises the question of reusing this pattern across multiple controllers and forms. So the answer was updated to address reuse of this pattern.
To simplify this for reuse, you could put this block in a helper function that is referenced in the before_filter for actions that require it.
def login
unless params[:session].nil?
self.current_user = User.authenticate(params[:session][:login], params[:session][:password])
if logged_in?
flash[:notice] = "Logged in successfully"
else
flash[:error] = "Incorrect username and or password."
end
end
end
as in:
before_filter :login => :only [:new , :edit, :update, :delete]
On the view side, it shouldn't be too hard to construct a new variant of form_for that embeds the session parameters. Maybe form_for_with_session?
As for handling an unsuccessful response, I would suggest helper function that takes a block of code. Sorry I don't have time to write out or test one for you.
You keep it in the session. So after logging in, when the user goes back to asking his question, you see there's already something in session.
And you can directly display it.
def create
if current_user # Implement this method in your auth framework
#question = Question.new(params[:question] || session.delete[:question])
# (the usual stuff you'd do to save)
else
session[:question] = params[:question]
redirect_to :controller => :sessions, :action => "new"
end
end
Then, after your user creation and authentication stuff is all done in your login action, just make sure you POST back to this create action if session[:question] is defined.

Resources