Create devise user and profile model with same form in rails - ruby-on-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.

Related

has_one belongs_to association attribute validation

I use devise for user authentication. Have two models User and Profile which are associated to each other like this
#app/model/user.rb
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_one :profile, dependent: :destroy
enum role: [:admin, :seller, :buyer]
end
#app/model/profile.rb
class Profile < ApplicationRecord
belongs_to :user
end
As you can see I have also role for users.
Here is forms for registrations of both models.
#user registration form
<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
...
<%= f.select :role, collection: User.roles.keys.last(2) %>
<%= f.input :mobile_number, required: true, autofocus: true %>
...
<% end %>
#profile registration form
<%= simple_form_for(#profile) do |f| %>
...
<% if current_user.seller? %>
<%= f.input :location, required: true %>
<% else %>
<%= f.input :company_code, required: true %>
<% end %>
...
<% end %>
Problem
When current user is seller I need to validate presence of :location , when user is buyer then validate presence of :company_code.
How can I achieve that? I appreciate any helps , Thanks!
validates method accepts if option:
# app/model/profile.rb
class Profile < ApplicationRecord
belongs_to :user
validates :location, presence: true, if: "user.seller?"
validates :company_code, presence: true, if: "user.buyer?"
end
Also, current_user.role == "seller" is obsolete. Rails automatically sets up additional methods in model for enum option values, therefore you may just write: current_user.seller?, etc.

Why are the nested resources for Devise authentication not working?

My rails app has a few cab operators and they have a few cabs, and they are related as follows:
class Operator < ActiveRecord::Base
has_many :cabs
end
I wish to add authentication system so as to create admins for each operator. I am using Devise. Since I need to create path as: operator/:operator_id/admins/sign_up, I generated the Admin model, as:
rails generate devise Admin
Then I modified my routes so as to obtain the above mentioned path:
scope "operators/:operator_id" do
devise_for :admins
end
Running rake routes shows that I am getting the required urls. I also modified the models:
class Admin < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
belongs_to :operator
end
class Operator < ActiveRecord::Base
has_many :admins
end
I also modified the devise/sessions/new.html.irb to include a hidden field for operator_id:
h2>Log in
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<div><%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %></div>
<div><%= f.label :password %><br />
<%= f.password_field :password, autocomplete: "off" %></div>
<% if devise_mapping.rememberable? -%>
<div><%= f.check_box :remember_me %> <%= f.label :remember_me %></div>
<% end -%>
<% f.hidden_field :operator_id, :value => params[:operator_id] %>
<div><%= f.submit "Log in" %></div>
<% end %>
<%= render "devise/shared/links" %>
Finally, in order to authenticate admins before accessing the cab details, I added the following to the cabs_controller:
before_filter :authenticate_admin!
The problem is I am unable to submit the admin form. The form doesn't respond when I submit the admin credentials. Where am I going wrong?
You have to add :operator_id to Devise's permitted parameters
Take a look here
Essentially, you want to go with following in application_controller.rb:
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) do |u|
u.permit(:email, :password, :password_confirmation, :operator_id) #add :operator_id
end
end

RoR NoMethodError in Credits#new

Hi,
I am doing my homework around the building a simple RoR app and got stuck with the following:
I created a Scaffold called "Credit", and a relationship between the User and Credit model:
Here are my files
credit.rb
class Credit < ActiveRecord::Base
attr_accessible :amount, :user_id
belongs_to :user
belongs_to :merchant
end
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
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me,
:first_name, :last_name, :profile_name
# attr_accessible :title, :body
has_many :statuses
has_many :merchants
has_many :credits
def full_name
first_name + " " + last_name
end
end
When trying to create a new credit entry with the following form:
<%= simple_form_for(#credit) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :amount %>
<%= f.input :user_id, collection: User.all %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
I get the following error,
NoMethodError in Credits#new
Showing/Users/andreucasadella/rails_projects/monedero/app/view credits/_form.html.erb where line #6 raised:
undefined method `user_id' for #
Any idea?

One to One relation between tables in Rails

Just started my first project in ROR and i'm facing a problem with build a relation between table.
As a noob i search a lot around the web, try plenty of stuff but can't figure out how to get this working.
Here's my issue: I built a User table for the login function - made with devise, now i want to build another table UserMeta to carry all the profile info of my users.
Here is the code of what i did:
app/models/user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :remember_me
attr_accessible :email, :encrypted_password
has_one :user_meta
end
*app/models/user_meta.rb*
class UserMeta < ActiveRecord::Base
attr_accessible :admin, :birthday, :company, :first_name, :job, :last_name, :phone, :rfid, :statut, :website, :user_id
belongs_to :users
end
class User
has_one :user_meta
end
*app/controllers/user_controllers.rb*
def new
#user = User.new
#meta = UserMeta.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #user }
end
end
app/views/users/new.html.erb
<%= form_for(#meta) do |f| %>
<div class="field">
<%= f.label :phone %><br />
<%= f.text_field :phone %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
It returns :
undefined method `meta_index_path' for #<#<Class:0x000001016f3f18>:0x00000100e9f6f0>
I know there is one or many mistake, what the best way to do this ? Some help will be appreciated :)
You can change to like this:
app/models/user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :remember_me, :encrypted_password
has_one :user_meta
accepts_nested_attributes_for :user_meta
end
app/models/user_meta.rb
class UserMeta < ActiveRecord::Base
attr_accessible :admin, :birthday, :company, :first_name, :job, :last_name, :phone, :rfid, :statut, :website, :user_id
belongs_to :user
end
app/controllers/user_controllers.rb
def new
#user = User.new
#user.build_meta_user
respond_to do |format|
format.html
format.json { render json: #user }
end
end
app/views/users/new.html.erb
<%= form_for #user, :url => {:action => 'create'} do |f| %>
<!-- User related fields -->
<%= f.fields_for :user_meta do |meta_f| %>
<div class="field">
<%= meta_f.label :phone %><br />
<%= meta_f.text_field :phone %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
In Rails it's best to name your classes the same as your filenames. So app/models/user_meta.rb should be class UserMeta < ActiveRecord::Base.
There's no need to re-open the User-class in app/models/user_meta.rb. He'll know about app/models/user.rb already.
Change your belongs_to :users to belongs_to :user
In app/models/user.rb you can drop the 2nd attr_accessible :email.

rails devise: user and account model

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

Resources