has_one belongs_to association attribute validation - ruby-on-rails

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.

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.

'merge' error with check_box field in rails

In my Rails app, I need to show user email id's with checkboxes in a form to allocate users to a particular project. I have an array object #programmers and each row in the object contains email id's which I need to show inside the form with checkboxes.
My partial view containing form is:
_allocate_programmer.html.erb
<h1> Allocate programmers </h1>(Please check the programmers that you want to add)<br />
<%= form_for(#project) do |f| %>
<% if #project.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#project.errors.count, "error") %> prohibited this project from being saved:</h2>
<ul>
<% #project.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<% unless #programmers.nil? %>
<% #programmers.each do |programmer| %>
<%= f.check_box :programmer, programmer.email %>
<% end %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
My routes.rb has:
match 'projects/:id/allocate_programmers' => 'projects#allocate'
My projects_controller.rb has the following code:
def allocate
#project = Project.find(params[:id])
#programmers = User.where(:role => 'programmer')
render "_allocate_programmer"
end
I am getting following error in the view
NoMethodError in Projects#allocate
Showing /home/local/Rajesh/ticket_system/app/views/projects/_allocate_programmer.html.erb where line #18 raised:
undefined method 'merge' for "test#gmail.com":String
I think its an issue with checkbox hash. Please help.
User.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :token_authenticatable,
:rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :role
# attr_accessible :title, :body
has_many :assignments
has_many :projects, :through => :assignments
has_many :tickets
ROLES = ['admin', 'network/system admin', 'manager', 'programmer']
def role?(base_role)
ROLES.index(base_role.to_s) <= ROLES.index(role)
end
end
Project.rb
class Project < ActiveRecord::Base
attr_accessible :project_name, :description, :duration_from, :duration_upto, :user_id
has_many :assignments
has_many :users, :through => :assignments
validates :project_name, :presence => true
validates :description, :presence => true
validates :duration_from, :presence => true
validates :duration_upto, :presence => true
#validates :user_id, :presence => true //this gives error
end
Assignment.rb
class Assignment < ActiveRecord::Base
attr_accessible :user_id, :project_id
belongs_to :user
belongs_to :project
end
Please check. I have updated the question with 3 models.
Supposing that you have set up your associations correctly.
<% #programmers.each do |programmer| %>
<%= check_box_tag "project[programmer_ids][]", programmer.id, #project.programmers.include?(programmer) %>
<%= programmer.email %>
<% end %>
ref this
check_box does not work when the check box goes within an array-like parameter
Following should work for you
<% #programmers.each do |programmer| %>
<%= check_box_tag "project[programmer]", programmer.email %>
<% end %>

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.

many to many association

So I have a model below that represents the situation:
Students participate in Contests.
Contests measure certain skills.
For each contest, each student gets a score for each skill measured.
Here are my models:
class Student < 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
attr_accessible :name
has_and_belongs_to_many :skills
has_many :contest_participations
has_many :contests, :through => :contest_participations
has_many :contest_scores, :through => :contests
end
class Skill < ActiveRecord::Base
attr_accessible :name
has_and_belongs_to_many :students
end
class Contest < ActiveRecord::Base
attr_accessible :name, :contest_participations_attributes, :contest_scores_attributes
has_many :contest_participations
has_many :students, :through => :contest_participations
has_many :contest_skills
has_many :skills, :through => :contest_skills
has_many :contest_scores
accepts_nested_attributes_for :contest_participations, :contest_scores
end
class ContestParticipation < ActiveRecord::Base
attr_accessible :contest_id, :student_id
belongs_to :student
belongs_to :contest
end
class ContestScore < ActiveRecord::Base
attr_accessible :contest_id, :score, :skill_id, :student_id
has_and_belongs_to_many :contests
has_and_belongs_to_many :skills
has_and_belongs_to_many :student
end
In my contests edit view, I'm trying to create a form, with formtastic, that will show all contest participants, and allow the user to add a score for each skill in the contest as follows.
But I get an error (student_id invalid symbol). How can I update the student scores?
<%= semantic_form_for #contest do |f| %>
<%= f.input :name %>
<%= #contest.students.each do |student| %>
<%= #contest.skills.each do |skill| %>
<%= f.inputs :name => "Scores", :for => :contest_scores do |scores_form| %>
<%= scores_form.input :student_id => "student.id" %>
<%= scores_form.input :skill_id => "skill.id" %>
<%= scores_form.input :score, :label => "Score" %>
<% end %>
<br />
<% end %>
<% end %>
<%= f.actions do %>
<%= f.action :submit, :as => :button %>
<% end %>
<% end %>
Try this. Added hidden because e think you don't want ids to show up
<%= scores_form.input :student_id, :as => :hidden, :value => student.id %>
<%= scores_form.input :skill_id, :as => :hidden, :value => skill.id %>

mass assignment selecting childs of user, using Devise

I have a very simple issue:
User model:
class User < ActiveRecord::Base
devise :database_authenticatable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :id, :email, :password, :password_confirmation, :remember_me,
:firstname, :lastname, :mobile_phone, :user_type, :department_id, :department_attributes
belongs_to :department
accepts_nested_attributes_for :department, :allow_destroy => false
Departments model:
class Department < ActiveRecord::Base
has_many :users
accepts_nested_attributes_for :users, :allow_destroy => true
I created a form to be able to select my departments member from my existing users using simple_form:
<%= simple_form_for #department, :validate => true do |form| %>
<%= form.error_messages %>
<%= form.association :users, :prompt => 'assign a user', :label => 'User'%>
<%= form.button :submit %>
<% end %>
Then I (try to) update my users via the department controller:
def update
#department = Department.find(params[:id])
respond_to do |format|
if #department.update_attributes(params[:department])
...
This generates following error:
WARNING: Can't mass-assign protected attributes: user_ids
My guess is that some devise settings generate this error but I don't know which ones.
Can you help? Thanks!
Add attr_accessible :user_ids to your Department model.

Resources