subsriber.rb
class Subscriber < ActiveRecord::Base
validates_confirmation_of :email, :message => "Your emails don't match!"
end
I have this in my rails app. When I create a new record without matching email
Here's my create action:
def create
#subscriber = Subscriber.new(params[:subscriber])
if #subscriber.save
redirect_to root_path, :notice => "You've been subscribed!"
else
render 'new'
end
end
How do I make the error message show up in the view file? I don't see anything in the docs saying I need to add something to my views but the message is not showing up.
You actually do need to add something to your view to show the message.
Rails normally does this for you when you create a scaffold, but if you need to do it manually for a field, you need to add something like this to your HTML template:
<%= f.error_messages_for :email_confirmation %>
Related
I have two partial views for two different sign up forms. On my home page , based on the link one clicks on, I'm rendering respective form.(views/application/index)
= link_to 'Mentor', new_user_path(user_role: true), :class =>'btn'
= link_to 'Mentee', new_user_path, :class =>'btn'
In views/users/new.html.haml , I'm checking the user role and redirecting to the respective form.
- if params[:user_role]
= render 'mentor'
- else
= render 'mentee'
In the user model I've added validation like this.
class User < ActiveRecord::Base
email_regex = /\A[\w+\-.]+#cisco.com/i
validates :cisco_email, :presence => true,
:format => { :with => email_regex,}
validates :work_city, :presence => true
end
So, when there is any invalid field I want to direct to the same form with a flash message. My controller looks like this.
class UsersController < ApplicationController
def index
end
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.new(params[:user]) # Not the final implementation!
if #user.save
flash[:success] = "Welcome to the CSG Mentoring Tool!"
redirect_to #user
else
flash[:notice] = "Error regsitering."
if params[:user][:user_role]
render :partial => 'users/mentor'
else
render :partial => 'users/mentee'
end
end
end
end
When an invalid field entry is there, it is redirecting to 'mentee' page no matter on which page the error is made. Also the entire css styling gets changed and flash is also not displayed
Why this is not working?
if params[:user][:user_role]
render :partial => 'users/mentor'
else
render :partial => 'users/mentee'
end
params[:user][:user_role] is nil.
You can check it using lots of way:
Above your if condition raise params[:user].inspect
Why its nil?
Reason of this is You are passing new_user_path(user_role: true) user_role true, but user_role is not true in mentor form.
params[:user_role] will not set user_role = true field in mentor form.
Set user_role
<%=f.hidden_field :user_role, value: params[:user_role] %>
If its supposed to be true for mentor always
<%=f.hidden_field :user_role, value: true %>
By default flash will make them available to the next request, but sometimes you may want to access those values in the same request.
Reference
This works with redirection
flash[:success] = "Welcome to the CSG Mentoring Tool!"
This will work with render
flash.now[:success] = "Welcome to the CSG Mentoring Tool!"
I'm trying to create a mailer that sends out an email whenever a user signs up. Pretty simple but I'm new to rails.
I have a site that already creates the user. I have a login and sign up page that works correctly, but need some help creating a mailer that sends out an email confirmation link and possibly an option to send out these emails without the user signing up like make a separate page for user invitations.
I've generated a model invitation.rb
class Invitation < ActiveRecord::Base
belongs_to :sender, :class_name => 'User'
has_one :recipient, :class_name => 'User'
validates_presence_of :recipient_email
validate :recipient_is_not_registered
validate :sender_has_invitations, :if => :sender
before_create :generate_token
before_create :decrement_sender_count, :if => :sender
private
def recipient_is_not_registered
errors.add :recipient_email, 'is already registered' if User.find_by_email(recipient_email)
end
def sender_has_invitations
unless sender.invitation_limit > 0
errors.add_to_base 'You have reached your limit of invitations to send.'
end
end
def generate_token
self.token = Digest::SHA1.hexdigest([Time.now, rand].join)
end
def decrement_sender_count
sender.decrement! :invitation_limit
end
#attr_accessible :sender_id, :recipient_email, :token, :sent_at
end
and my invitiation_controller.rb
class InvitationsController < ApplicationController
def new
#invitation = Invitation.new
end
def create
#invitation = Invitation.new(params[:invitation])
#invitation.sender = current_user
if #invitation.save
if logged_in?
Mailer.deliver_invitation(#invitation, signup_url(#invitation.token))
flash[:notice] = "Thank you, invitation sent."
redirect_to projects_url
else
flash[:notice] = "Thank you, we will notify when we are ready."
redirect_to root_url
end
else
render :action => 'new'
end
end
end
What else do I need to edit? how do I hook this up to an already existing user signup and login that is working fine?
You should already have a UsersController or something like that for registration purposes, which you currently access through the signup_url named route. Suppose that this route is now something like:
http://localhost:3000/register/code_here
All you have to do now is check for the invitation in the controller action and process it accordingly like so:
def new
invite = Invite.find_by_token(params[:id]
if invite.nil?
redirect_to root_path, :notice => "Sorry, you need an invite to register"
end
#user = User.new(:email => invite.recipient_email)
end
def create
invite = Invite.find_by_token(params[:token]
if invite.nil?
redirect_to root_path, :notice => "Sorry, you need an invite to register"
end
begin
invite.nil.transaction do
invite.nil.destroy!
#user = User.create(params[:user)
end
redirect_to my_dashboard_path, :notice => "Yay!"
rescue ActiveRecord::RecordInvalid => invalid
render :new, :alert => "Validation errors"
end
end
Without the invite code, you will simply redirect to root page. You may want to DRY that check though. When someone uses the invite code, you may want to delete it from the database. I wrapped it up in a transaction, but this is up to you (creating the user may be more important).
If you want to create a page that allows users to create invitations without signing up, then simply don't add authentication to InvitationsController and update this snippet:
def create
#invitation = Invitation.new(params[:invitation])
#invitation.sender = current_user if logged_in?
if #invitation.save
Mailer.deliver_invitation(#invitation, signup_url(#invitation.token))
flash[:notice] = "Thank you, invitation sent."
if logged_in?
redirect_to projects_url
else
redirect_to root_url
end
else
render :action => 'new'
end
end
I'm not sure if I covered all the bases, but I think this should point you in the right direction at least.
I can not see where Mailer.deliver_invitation comes from, do you use a gem? would it help if you would create mailer.rb, do you have any error mgs/ stack trace?
Have a look here there are some guides, 5 Action Mailer Configuration
http://guides.rubyonrails.org/action_mailer_basics.html
Consider using devise for user authentication, https://github.com/plataformatec/devise
It is complex, but well documented and easy to configure to jump start.
I assume you are using Rails 3.1 (works also in earlier versions, just find the right guide to your Rails version, to be sure)
How can you pass an error messages coming from a model --> controller to view?
= form_tag :controller => "article", :action => "create" do
/ how to retrieve error messages here?
%p
= label_tag :article, "Article"
= text_field_tag :article
= submit_tag "Submit Article"
I have this model:
class Article < ActiveRecord::Base
attr_accessible :article
validates :article, :presence => true
end
In my controller:
def create
#article = Article.new(params[:article])
if ! #article.save
# how to set errors messages?
end
end
I'm using Rails 3.0.9
The errors messages are stored in your model. You can access through the errors methods, like you can see in http://api.rubyonrails.org/classes/ActiveModel/Errors.html.
An easy way to expose the error message is including the follow line in your view:
%span= #article.errors[:article].first
But, I belive you have to change your controller to be like that:
def new
#article = Artile.new
end
def create
#article = Artile.new params[:article]
if !#article.save
render :action => :new
end
end
In the new action you don't need to try save the article, because the creation action already do that job. The new action exists, (basically) to call the new view and to provide support for validations messages.
The newmethod shouldn't save anything. create method should.
def create
#article = Article.new(params[:article])
if ! #article.save
redirect_to root_path, :error => "ops! something went wrong.."
end
end
I have been using Wicked_pdf to render a view as a PDF and actionmailer to send emails, but I can't get them to work together. I want to attach a PDF version of a certain view to an email using actionmailer and send it out by clicking a link or a button. I have a link_to command that sends out an email. Here is my controller that gets the email generated:
def sendemail
#user = User.find(params[:id])
Sendpdf.send_report(#user).deliver
redirect_to user_path(#user)
flash[:notice] = 'Email has been sent!'
end
Here is what I have in my actionmailer:
class Sendpdf < ActionMailer::Base
default :from => "myemail#email.com"
def send_report(user)
#user = user
attachment "application/pdf" do |a|
a.body = #Something should go here, maybe WickedPDF.new.something?
a.filename = 'MyPDF'
end
mail(:to => user.email, :subject => "awesome pdf, check it")
end
end
I have seen many questions and answers, most dealing with Prawn. It seems like there should be a simple answer to this. Can anyone help?
UPDATE I'm grateful for a suggestion to use as an alternative option in the answer below. However, I would really like to learn how to render a view as a PDF and attach it to my email. I am open to using something different like Prawn or anything else if I need to.
2 good ways to do this the way you want:
1: Create the pdf in the controller, then send that to the email as a param.
# controller
def sendemail
#user = User.find(params[:id])
pdf = render_to_string :pdf => 'MyPDF'
Sendpdf.send_report(#user, pdf).deliver
redirect_to user_path(#user)
flash[:notice] = 'Email has been sent!'
end
# mailer
def send_report(user, pdf)
#user = user
attachments['MyPDF.pdf'] = pdf
mail(:to => user.email, :subject => "awesome pdf, check it")
end
2: Create the pdf in the mailer directly (a little more involved, but can be called from a model)
def send_report(user)
#user = user
mail(:to => user.email, :subject => "awesome pdf, check it") do |format|
format.text # renders send_report.text.erb for body of email
format.pdf do
attachments['MyPDF.pdf'] = WickedPdf.new.pdf_from_string(
render_to_string(:pdf => 'MyPDF',:template => 'reports/show.pdf.erb')
)
end
end
end
There are 2 ways for it.
Either, you want the pdf to be embedded in the email you are sending, so that when the user downloads the pdf from the email, there is no request to the render new pdf action for your respective controller.
I don't know how to do this efficiently because I have never done this before.
Or, you just provide a link to the pdf in your email and when the user clicks on it, now the action for creating the pdf is called, and then the user can download it.
This way, if there is a lot of burden on the server for the downloading of the pdf's, you can redirect these requests somewhere else. In short, there is a huge scope for efficiency.
A sample code for the 2nd method(code provided was written by using PDFkit, so change accordingly):
class PdfsController < ApplicationController
def pdf
respond_to do |format|
format.pdf { render :text => wickedPDF.new( Pdf.find(params[:id]).content ).to_pdf }
end
end
...
end
Replace the Pdf.find(params[:id]).content as per your choice, and the to_pdf method, as per wickedPDF.
Then, you can simply pass the link for the pdf download in your email like this
<%= link_to "Download", pdf_pdf_path(pdf, :format => "pdf") %>
or whatever suits as per wickedPDF.
I have an object Tasks with a model like this
has_many :notes, :validate => true
And Notes with a model like this:
belongs_to :task
validates_presence_of :body, :message => "cannot be empty, bonehead!"
I have a /tasks/new view to create a new task (form _for), and a note for it (fields _for). I want the validation failure messages for the Task and Note to be spat out at the top of the form.
The controller looks like:
def create
#task = Task.new(params[:task])
#note = Note.new(params[:note])
#task.notes << #note
if #task.save
redirect_to tasks_path
else
render :action => 'new'
end
The problem is, when no Note body is entered a validation error message is returned in #note, "Body cannot be blank, bonehead"; and another one in #task, "Note is invalid".
I'm spitting both out in the view like this:
<%= error_messages_for 'task', 'note', 'users_list', :header_message => nil, :message => nil %>
I want to keep the Note model validation message, and not have one as part of the Task object, "Not is invalid".
Thanks a lot!
I don't have a console in front of me, but I think if you change your if statement to if #note.valid? and #task.save it would check the note first and only give you the first message.
Edit: This is just kind of an FYI, but you might want to use build instead of two new statements:
def create
#task = Task.new(params[:task])
#note = #task.notes.build(params[:note])
if #task.save
...