rails devise: user and account model - ruby-on-rails

Hi I am trying to customize the sign up page by adding an additional field, name.
This is done by adding a Profile model to my app.
class Profile < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :profile_attributes
has_one :profile, :dependent => :destroy
accepts_nested_attributes_for :profile
end
I overrode the registration model:
# app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def new
super
profile = #user.build_profile
end
def create
super
end
def update
super
end
end
And my new sign up page:
<h2>Sign up</h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<div><%= f.label :password %><br />
<%= f.password_field :password %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></div>
<div><% f.fields_for :profile do |builder| %>
<p><%= builder.label :name %></p>
<p><%= builder.text_field :name %></p>
<% end %></div>
<div><%= f.submit "Sign up" %></div>
<% end %>
<%= render "links" %>
However, I am not sure if everything else works, but the registration page still looks the same. That is, it doesn't show the name input field. How do I fix this?
What am I missing?

I suspect you did not generate the views. Did you run the following?
rails generate devise:views
More information on changing views can be found in "Configuring views" on the devise wiki:
https://github.com/plataformatec/devise
Thanks,
Tabrez

Related

Create devise user and profile model with same form in rails

I'm looking to create a form with input fields for two models - Devise User model and Profile model. I want the profile model to be created with the fields and reference the User model when created.
Registration New view
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<!-- Devise Fields for User model -->
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
<%= f.password_field :password, autocomplete: "new-password" %>
<%= f.password_field :password_confirmation, autocomplete: "new-password" %>
<!-- Profile model -->
<%= f.fields_for :profile do |g| %>
<%= g.text_field :first_name %>
<%= g.text_field :last_name %>
<% end %>
<%= f.submit "Sign up" %>
<% end %>
User Model
has_one :profile, dependent: :destroy
attr_accessor :first_name, :last_name
accepts_nested_attributes_for :profile
Profile Model
belongs_to :user
Application Controller
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [ profile_attributes: [:first_name, :last_name]])
end
Devise Registration controller (override)
def new
super do |resource|
resource.build_profile
end
end
After filling out the form I receive an error message. Refer to the following image
Here is the code on Github https://github.com/Goeken/Speech-today
How should I go about this?
I had look into your github repository code & I found that your User model code is not correct. Here's the modified user model -
class User < ApplicationRecord
has_one :profile, dependent: :destroy
# You should not add first_name last_name validation message here,
# because those are profile model attributes, Not user model
#validates_presence_of :first_name, :last_name
accepts_nested_attributes_for :profile
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
And rest of code are OK.
I hope it will work.

rails undefined method status

This is a very easy question I am using devise for authentication...So I am trying to modify my sign up .I am trying to add a radio button on my sign up but it is giving me error .undefined method `status' for User:0x00000001a66368. So i want to know why i can't use radio button on my sign up page
[registration/new.html.erb]
<h2>Sign up</h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %></div>
<div><%= f.label :password %> <% if #validatable %><i>(<%= #minimum_password_length %> characters minimum)</i><% end %><br />
<%= f.password_field :password, autocomplete: "off" %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %></div>
<div >
<%= f.label 'InActive' do %>
<%= f.radio_button :status,'In Active'%>
<% end %>
</div>
<div><%= f.submit "Sign up" %></div>
<% end %>
<%= render "devise/shared/links" %>
[user.rb]
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :posts
has_many :comments
validates :status,presence:true
validates :name, presence: true
def self.find_role(id)
User.find(id).roles
end
end
You need to add status field in the user table.
rails g migration add_user_status_to_user user_status:boolean
rake db:migrate
Then , In application controller, use strong parameters
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << [:user_status]
end
end
rails generate migration add_status_to_user status:boolean
rake db:migrate
You need to by pass Strong Parameters to add additional new attributes to the sign up page.
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up).push(:status)
end
end

Create nested forms using Devise

I'm trying to build a nested form using Devise, keeping the devise featuring as sending an email when a new user signs up. I would like to have something like this:
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<%= f.fields_for(:information) do |info| %>
<div><%= info.text_field :name, :placeholder => 'Nome' %></div>
<div><%= info.text_field :surname, :placeholder => 'Cognome' %></div>
<% end %>
<div><%= f.email_field :email, :autofocus => true, :placeholder => 'E-mail' %></div>
<div><%= f.password_field :password, :placeholder => 'Password' %></div>
<div><%= f.password_field :password_confirmation, :placeholder => 'Conferma password' %></div>
<div><%= f.submit "Registrati", class: "btn btn-large btn-info" %></div>
<% end %>
In my route.rb
devise_for :users, :controllers => { :registrations => "users" }
In my user.rb
class User < ActiveRecord::Base
has_one :information, dependent: :destroy
# Include default devise modules. Others available are:
# :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable,
:validatable, :confirmable, :lockable
accepts_nested_attributes_for :information, update_only: true
end
and in information.rb
class Information < ActiveRecord::Base
belongs_to :user
end
in users_controller.rb
class UsersController < Devise::RegistrationsController
def new
super
resource.build_information
end
end
But nothing happen, or better the 2 fields name and surname don't appear, but I don't receive an error message
Here is what I would do,
I would move this line from the controller to the view(fields_for takes 2 parameters). Like below,
Controller
def new
super
resource.build_information #remove from here
end
View
<!--Added here -->
<%= f.fields_for(:information,resource.build_information) do |info| %>
Must work now!
OR
Just change
<%= form_for(resource, :as => res.....
to
<%= form_for(#resource, :as => res
Note "#", this will work. Remove build_information both from view and controller.

rails devise user external api

I am trying to setup a newsletter signup procedure when a new user signs up. I am using Mailchimp via gibbon to handle the newsletters. I have added a subscribe attribute to my model and a getter and setter method. I also have added the subscribe checkbox to my form. What I need to do is if the form box is checked subscribe the user to the email on creation.
model
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :username, :subscribe
validates :username, presence: true
validates_uniqueness_of :username
has_many :contest_entries, dependent: :destroy
has_many :votes, dependent: :destroy
def subscribe=(join)
puts "called subscribe with #{join}"
if join
Gibbon.new.list_subscribe(:id => "blah", :email_address => self.email)
end
end
def subscribe
subscribe ||= false
end
end
Form view
<h2>Sign up</h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<p><%= f.label :username %><br />
<%= f.text_field :username %></p>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<div><%= f.label :password %><br />
<%= f.password_field :password %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></div>
<div><%= f.label :subscribe, "Subscribe to Newsletter?" %><br />
<%= f.check_box :subscribe, :checked => true %></div>
<div><%= f.submit "Sign up" %></div>
<% end %>
<%= render "devise/shared/links" %>
I was hoping that by adding the attr_accessible and a method it would call the api from the contoller automatically, but it does not seem to be called.
Any advice on how to handle this? I could also use advice on how to test with RSPEC to make sure it is being called.
Thanks,
Cory
Ok I figured out the issue. The problem was with the check for join inside the setter method. Since it was a checkbox, I needed to check for a matching integer of 1.
def subscribe=(join)
begin
if join.to_i == 1
gb = Gibbon.new
result = gb.list_subscribe(:id => "blah", :email_address => self.email)
end
rescue
false
end
end

How to avoid "Can't mass-assign protected attributes" error

Even though I added accepts_nested_attributes_for to my model.
it still says "Can't mass-assign protected attributes"
What else am I supposed to do in order to avoid this???
models/user.rb
class User < ActiveRecord::Base
validates_presence_of :username
validates_uniqueness_of :username
validates_length_of :username, :within => 4..10
acts_as_messageable
has_one :user_profile
accepts_nested_attributes_for :user_profile
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :username, :user_profile_attributes
def mailboxer_email(message)
email
end
# def name
# email
# end
end
models/user_profile.rb
class UserProfile < ActiveRecord::Base
belongs_to :user
accepts_nested_attributes_for :user
attr_accessible :nickname
end
views/registration/edit.html.erb
<h2>Edit <%= resource_name.to_s.humanize %></h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :nickname %><br />
<%= f.fields_for :nickname_attributes, #user.user_profile do |user_profile| %>
<%= user_profile.text_field :nickname %>
<% end %>
</div>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<div><%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
<%= f.password_field :password %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></div>
<div><%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password %></div>
<%= recaptcha_tags :display => {:theme => 'red'} %>
<div><%= f.submit "Update" %></div>
<% end %>
<h3>Cancel my account</h3>
<p>Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), :confirm => "Are you sure?", :method => :delete %>.</p>
<%= link_to "Back", :back %>
attr_accessible defines the attributes you want the user to be able to mass assign. Just make sure it has all the attributes you want in there.
To be fair, you can remove attr_accessible if you don't care about it and the error will disappear (but all your model fields will be mass assignable).
in edit.html.erb
wrong:
f.fields_for :nickname_attributes,
correct:
f.fields_for :user_profile_attributes,

Resources