rendering the partials in controller after the validation check - ruby-on-rails

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!"

Related

Could find Addict without an ID

I'm trying to put a new form that creates new "Addicts" in a modal in my home page.
It's a simple form with 2 inputs, that when clicking on New, a modal pops up with that form in my index page.
I can't get it to work because it keeps saying "Couldnt find Addict without an ID".
My Pages Controller
class PagesController < ApplicationController
def home
#addict = Addict.find(params[:id])
#lanzaderas = Lanzadera.all
render 'index'
end
end
My Addict Controller
class AddictsController < ApplicationController
def index
#posts = Addict.all
end
def show
#addict = Addict.find(params[:id])
end
def new
#addict = Addict.new(params[:addict])
end
def create
#addict = Addict.new(params[:addict])
if #addict.save
redirect_to posts_path, :notice => "Your Addict was saved"
else
render "new"
end
end
def edit
end
def update
end
def destroy
end
end
end
My form in my modal
<%= form_for #addict do |f| %>
<%= f.input :name %>
<%= f.input :surname %>
<%= f.input :postal %>
<%= f.submit %>
<% end %>
I know it has something to do with the variable / id not being passed correctly in my Controller, but it's an error I get lots of times and don't know why I happens.
Thanks!
In def home in your PagesController you have this code:
#addict = Addict.find(params[:id])
I suspect, that you don't have the id for 'addict' in your parameters, when you visit your home action.
Do you want to display one particular addict in your 'home' page? If not, you can remove this line.
Update:
Change this in your AddictsController:
def new
#addict = Addict.new
end
In the new action you only "prepare" a new addict object. Using the find method is not possible, since the record hasn't been created yet.
If you're using Rails 4 you also have to permit your parameters (for security reasons; more info here: Railsguides: Strong Parameters)
In your case you have to do 2 things:
First: add this at the bottom of your AddictsController:
private
def addict_params
params.require(:addict).permit(:name, :surname, :postal)
end
Second: use this method in your create action instead of params[:addict]:
def create
#addict = Addict.new(addict_params)
if #addict.save
redirect_to posts_path, :notice => "Your Addict was saved"
else
render "new"
end
end

How to generate Unsubscription link for emails of Actionmailer?

I have a table CLIENTS with id, name and email fields and I am sending them emails using ActionMailer with 3rd party SMTP.
Now I want the clients to have subscription option too so I added "subscription" column with default value as true.
Now how to generate a link which can be put in views mailer template so when the user clicks on it, the subscription value changes to false so in future the client dont' get any email ? Do note that these clients are not my rails app users so I can't uses what is been suggested here Rails 3.2 ActionMailer handle unsubscribe link in emails
I found this link how to generate link for unsubscribing from email too which looked helpful but I thought may be in 3 years, we might have got a better solution
Here is my Complete Code -
#client.rb
attr_accessible :name, :company, :email
belongs_to :user
has_many :email_ids
has_many :emails, :through => :email_ids
before_create :add_unsubscribe_hash
private
def add_unsubscribe_hash
self.unsubscribe_hash = SecureRandom.hex
end
Here is Clients_controller.rb file
# clients_controller.rb
def new
#client = Client.new
respond_to do |format|
format.html
format.json { render json: #client }
format.js
end
end
def create
#client = current_user.clients.new(params[:client])
respond_to do |format|
if #client.save
#clients = current_user.clientss.all
format.html { redirect_to #client }
format.json { render json: #client }
format.js
else
#clients = current_user.clients.all
format.html { render action: "new" }
format.json { render json: #client.errors, status: :error }
format.js
end
end
end
def unsubscribe
#client = Client.find_by_unsubscribe_hash(params[:unsubscribe_hash])
#client.update_attribute(:subscription, false)
end
The code is working fine for existing records and the unsubscription is working perfectly, I am only having problem in creating new clients.
I have used #client in unsubscribe method as I am using this object in client_mailer.rb template (using #client or just using client, both are working!)
EDIT 2 -
_form.html.erb
<%= simple_form_for(#client, :html => {class: 'form-horizontal'}) do |f| %>
<%= f.input :name, :label => "Full Name" %>
<%= f.input :company %>
<%= f.input :email %>
<%= f.button :submit, class: 'btn btn-success' %>
<% end %>
I have copied the full track stack at http://jsfiddle.net/icyborg7/dadGS/
Try associating each client with a unique, but obscure, identifier which can be used to look up (and unsubscribe) the user via the unsubscribe link contained within the email.
Start by adding another column to your clients table called unsubscribe_hash:
# from command line
rails g migration AddUnsubscribeHashToClients unsubscribe_hash:string
Then, associate a random hash with each client:
# app/models/client.rb
before_create :add_unsubscribe_hash
private
def add_unsubscribe_hash
self.unsubscribe_hash = SecureRandom.hex
end
Create a controller action that will toggle the subscription boolean to true:
# app/controllers/clients_controller.rb
def unsubscribe
client = Client.find_by_unsubscribe_hash(params[:unsubscribe_hash])
client.update_attribute(:subscription, false)
end
Hook it up to a route:
# config/routes.rb
match 'clients/unsubscribe/:unsubscribe_hash' => 'clients#unsubscribe', :as => 'unsubscribe'
Then, when a client object is passed to ActionMailer, you'll have access to the unsubscribe_hash attribute, which you can pass to a link in the following manner:
# ActionMailer view
<%= link_to 'Unsubscribe Me!', unsubscribe_url(#user.unsubscribe_hash) %>
When the link is clicked, the unsubscribe action will be triggered. The client will be looked up via the passed in unsubscribe_hash and the subscription attribute will be turned to false.
UPDATE:
To add a value for the unsubscribe_hash attribute for existing clients:
# from Rails console
Client.all.each { |client| client.update_attribute(:unsubscribe_hash, SecureRandom.hex) }

Rails create or update Users

I am very very new to Rails and am struggling a little.
I have users that follow a basic sign up, edit process.
I have a situation where a user can be 'part registered', i.e a users email address in the db with a random password as they where put in there via an invite process by an existing user.
When an invited user who already technically exists in the db tries to register I get 'email already exists' since I do have uniqueness checks applied to the user object and a unique index on the table.
I did turn this off and using if statements within the create method to see if the user exists and checked other values did an update or a new and save. All of the if conditions were ignored and a new user was created.
What I want to do is use the same registration form that 'creates' a user to update an existing 'part registered' user with their entered password and name if they exist (email address check) and other db flags are set to true. if the user does exist but the conditions not met load a 'forgot password' page or if user is a new user create and save it.
Any assistance or advice on how to achieve the above would be brill.
Thanks
Vicky
Here is my set up:
User class
class User < ActiveRecord::Base
attr_accessor :password
attr_accessible :email, :name, :password, :password_confirmation, :tandc
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :name, :presence => true,
:length => { :maximum => 50 }
validates :email, :presence => true,
:format => {:with => email_regex },
:uniqueness => { :case_sensitive => false }
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 }
validates :tandc, :presence => true
before_save :encrypt_password
.
.
.
end
I have a UsersController with the following
def new
#user = User.new
#title = "Sign Up"
end
def create
if #user.save
sign_in #user
redirect_to #user
else
#title = "Sign up"
render 'new'
end
end
def update
if #user.update_attributes(params[:user])
redirect_to #user
else
#title = "Edit"
render 'edit'
end
end
.
.
.
I have views:
user > new.html.erb
<%= form_for(#user, :html => { :class => "validateUser", :name =>"edit_user"}) do |f| %>
.
.
.
form stuff here
.
.
.
<% end %>
and user > edit.html.erb
<%= form_for(#user, :html => { :class => "validateUser", :name =>"edit_user"}) do |f| %>
.
.
.
form stuff here
.
.
.
<% end %>
my routes for users are as follows
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
A quick, but not elegant solution could be:
def create
if user = User.find_by_email(params[:user][:email])
if user.part_registered?
user.update_attributes(params[:user])
user.save
sign_in user
redirect_to user
else
#user = User.new(params[:user])
if #user.save
# just to trigger the error messages ...
else
#title = "Sign up"
render 'new'
end
end
else
#user = User.new(params[:user])
if #user.save
sign_in #user
redirect_to #user
else
#title = "Sign up"
render 'new'
end
end
end
Sorry, i don't have time right now to optimize these conditions
First off, don't remove the unique index on the user's email. You need that to be unique if you are using it as the natural key of the model, aka signing in with it.
Ask yourself, what is the point of an invitation? I have a sneaking suspicion creating a new user is not really what you want the application to do... what if the user never takes up the inviter on the invitation?
Instead you could make an Invitation object with the user's email and the inviter (if that is the point of an invitation.) Then you could give a link that passes in the invitation as a parameter: <%= link_to new_user_url, email: invitation_email_here %> and put that link in, say, an email to the invited user.
In users/new.html.erb you could pass in the value to pre-fill the form with the email:
<%= f.email_field :email, value: params[:email] %>
Also, I would put your form in a partial to not repeat yourself.
The way form_for works, if #user is new, it will issue a POST request with the filled in values to the create action of the UsersController. If #user is an existing model, it will fill the form with the existing values, issue a PUT request to the update action of the UsersController.
Long story short the edit and new views can have the identical form. To simply display the same form, make a partial in the users/ veiws directory.
<!-- app/views/users/_form.html.erb -->
<%= form_for(#user, html: { class: "validateUser" }) do |f| %>
...
<% end %>
And then in the views where you would put the form, put <%= render 'users/form' %>
You can use something along the lines of User.find_or_initialize_by_email(:email => params[:user_email]) to get the User object.
Basically, find_or_initialize will attempt to get the User from the database, and if it fails to get anything it will create a new one that you can later save.
After you get your User object, you can perform whatever you want to its fields, and then save the result to the database (either updating the old entry or creating a new one).
(Note: if you want to check whether the User previously existed, use .persisted? on the object returned by find_or_initialize, this will return a boolean value telling you if it was already in the database.)
When someone registers with the site, you could send an account verification email before logging them in. The email includes a link with a system-generated token (e.g. 'User.token'). When they click the link, your verification_controller retrieves the user by their token and lets them set their password.
# In class User < ActiveRecord::Base
# Give the user a unique, random token
user.token = SecureRandom.urlsafe_base64(20)
# In class VerificationsController < ApplicationController
# Retrieve the user with their token
#user = User.find_by_token(params[:token])
Now let's consider your case. When an invited user tries to register before accepting an invite, you can still send an account verification email. Now they have two emails: 1) from the invite and 2) from their registration. It doesn't matter...they just have to click the link and set their password.
You will probably want to expire the token since it gives a way to access the account. A popular authentication framework, AuthLogic, has a password resets tutorial that is helpful. It shows a similar technique and might give you some ideas for your hand-built solution.
You could try in users_controller.rb
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #collection, notice: 'User was successfully updated.'}
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
the add link to your view
<%= link_to content_tag(:span, "Edit"), edit_user_path(#user), :class => 'edit' %>
in new.html.erb remove the form and add
<%= render 'form' %>
(this will render the partial that you will add form code to)
create _form.html.erb and add the form code to this
then create your edit.html.erb view and add code
<%= render 'form' %>

Pass Error Messages When Using form_tag?

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

Rails: Can you pass arguments to the after_create method?

In my application, only users with the administrator role may create new users. In the new user form, I have a select box for each of the available roles that may be assigned to new users.
I am hoping to use the after_create callback method to assign the role to the user. How can I access the selected value of the select box in the after_create method?
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
flash[:notice] = 'User creation successful.'
format.html { redirect_to #user }
else
format.html { render :action => 'new' }
end
end
end
In the user model I have:
after_create :assign_roles
def assign_roles
self.has_role! 'owner', self
# self.has_role! params[:role]
end
I receive an error because the model doesn't know what role is.
You could use attr_accessor to create a virtual attribute and set that attribute as part of your create action.
The short answer is, no. You cannot pass any arguments to after_create.
However what your trying to do is a pretty common and there are other ways around it.
Most of them involve assigning the relationship before the object in question is created, and let ActiveRecord take care of everything.
The easiest way to accomplish that depends on the relationship between Roles and Users. If is a one to many (each user has one role) then have your users belong to a role and sent role_id through the form.
<%= f.collection_select :role_id, Role.all, :id, :name %>
If there is a many to many relationship between users and roles you achieve the same by assigning to #user.role_ids
<%= f.collection_select :role_ids, Role,all, :id, :name, {}, :multiple => :true %>
The controller in either case looks like
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
flash[:notice] = 'User creation successful.'
format.html { redirect_to #user }
else
format.html { render :action => 'new' }
end
end
end

Resources