Rails 3 has_many :through Form - ruby-on-rails

Can't figure out why this is not working. First time using :has_many => :through
Keep getting uninitialized constant User::Employmentship
class User < ActiveRecord::Base
has_many :employmentships
has_many :companies, :through => :employmentships
accepts_nested_attributes_for :employmentships, :allow_destroy => true, :reject_if => proc { |obj| obj.blank? }
attr_accessible :email, :password, :password_confirmation, :firstname, :lastname, :username, :role, :company_ids
end
class Company < ActiveRecord::Base
has_many :employmentships
has_many :users, :through => :employmentships
end
/views/users/_form.html.erb
<p>
<%= for company in Company.all do %>
<%= check_box_tag "user[company_ids][]", company.id, #user.companies.include?(company) %>
<%= company.name%>
<% end %>
</p>
EDIT - If I change #user.companies.include?(company) to false i get the form, but nothing updates.
EDIT 2 -
class Employmentship < ActiveRecord::Base
belongs_to :company
belongs_to :user
attr_accessor :company_id, :user_id
end

Where is you employmentship model? has_many_through is for going through another model.

Related

Rails 4 unpermitted params error

I am receiving this error when a form submits:
Unpermitted parameters: postal_address_type_faos
I can confirm that the params come in ok but it looks like the postal_address_type_faos is being removed.
This is the params whitelist:
def paper_params
params.require(:paper).permit(:status, :signature_id, :name, :code,
:create_user_id, :update_user_id, :created_at, :updated_at,
phone_numbers_attributes: [:id, :phone_type_id, :area_code, :number, :extension, :create_user_id, :update_user_id, :created_at, :updated_at, :_destroy],
postal_addresses_attributes: [:id, :postal_address_type_id, :country_id, :line_1,:line_2, :line_3, :city, :territory_id, :postal_zip_code,
:address_note, :latitude, :longitude,
:_destroy, :address_verification_status_id, :comment,
postal_address_type_faos_attributes: [:id, :postal_address_id, :postal_address_type_id, :fao, :create_user_id, :update_user_id, :created_at, :updated_at, :_destroy]])
end
Models:
class Paper < ActiveRecord::Base
has_many :paper_postal_addresses
has_many :postal_addresses, through: :paper_postal_addresses
has_many :postal_address_type_faos, through: :postal_addresses
accepts_nested_attributes_for :postal_addresses
accepts_nested_attributes_for :postal_address_type_faos
has_many :phone_number_papers
has_many :phone_numbers, through: :phone_number_papers
accepts_nested_attributes_for :phone_numbers, allow_destroy: true
class PaperPostalAddress < ActiveRecord::Base
belongs_to :paper
belongs_to :postal_address
has_many :postal_address_type_faos, through: :postal_address
class PostalAddress < ActiveRecord::Base
has_many :postal_address_type_faos
has_many :postal_address_types, :through => :postal_address_type_faos
has_many :paper_postal_addresses
has_many :papers, through: :paper_postal_addresses
class PostalAddressTypeFao < ActiveRecord::Base
belongs_to :postal_address_type
belongs_to :postal_address
has_many :paper_postal_addresses, through: :postal_address
class PostalAddressType < ActiveRecord::Base
has_many :postal_address_type_faos
has_many :postal_addresses, through: :postal_address_type_faos
View code from the address partial is something like this
<%= f.fields_for :postal_addresses do |address|%>
//some address stuff here
//then do address fao type stuff (index is populated but not shown here)
<%= f.fields_for :postal_address_type_faos, #paper.postal_addresses[address.index].postal_address_type_faos[index] do |fa| %>
<%= fa.check_box :postal_address_type_id, label: fa.object.postal_address_type.name %>
<%= fa.text_field :fao, label: fa.object.fao %>
<% end %>
<% end %>
Params coming back as:
{"utf8"=>"✓", "authenticity_token"=>"R8ukkukuykuk",
"paper"=>{"carrier_id"=>"", "name"=>"", "status"=>"Active","digital_id"=>"1","signature_id"=>"1", "phone_numbers_attributes"=>{"0"=>{"create_user_id"=>"1568", "phone_type_id"=>"2", "country_phone_code_id"=>"2", "area_code"=>"",
"number"=>"", "extension"=>""}}, "postal_addresses_attributes"=>{"0"=>{"country_id"=>"", "line_1"=>"", "line_2"=>"", "line_3"=>"", "city"=>"", "territory_id"=>"", "postal_zip_code"=>"", "subterritory"=>"", "comment"=>""},
"1"=>{"country_id"=>"", "line_1"=>"", "line_2"=>"", "line_3"=>"", "city"=>"", "territory_id"=>"", "postal_zip_code"=>"", "subterritory"=>"", "comment"=>""},
"2"=>{"country_id"=>"", "line_1"=>"", "line_2"=>"", "line_3"=>"", "city"=>"", "territory_id"=>"", "postal_zip_code"=>"", "subterritory"=>"", "comment"=>""}},
"postal_address_type_faos_attributes"=>{"0"=>{"postal_address_type_id"=>"1", "attention"=>""}, "1"=>{"postal_address_type_id"=>"0", "fao"=>""}, "2"=>{"postal_address_type_id"=>"0", "fao"=>""}, "3"=>{"postal_address_type_id"=>"0",
"fao"=>""}, "4"=>{"postal_address_type_id"=>"0", "fao"=>""}}}, "area_code_required"=>"", "formaction"=>"add_address", "action"=>"create",
"controller"=>"papers"}
Just change view code from
<%= f.fields_for :postal_address_type_faos, #paper.postal_addresses[address.index].postal_address_type_faos[index] do |fa| %>
to
<%= address.fields_for :postal_address_type_faos, #paper.postal_addresses[address.index].postal_address_type_faos[index] do |fa| %>

Rails: Use a collection of checkboxes to add/remove entries on a different table with ActiveRecord

I have three objects: Contact, Sector, and Contact_sector.
Contact contains an id and some other irrelevant (non-reference) columns
Sector contains an id and sector column with ~10 editable entries
Contact_sector has a contact_id reference and a sector_id reference. In my mind I imagine that every sector that applies to some contact can be found here, and if a sector is un-applied it is removed from here.
I want to have a collection of checkboxes in the contact _form formed from list of entries in :sectors, but updating the form with certain boxes ticked adds/removes entries from :contact_sectors.
Where am I going wrong?
UPDATED: Fixed strong_params to permit sectors, now I am unable to find the sectors by id ActiveRecord::RecordNotFound (Couldn't find Sector with ID=["1", ""] for Contact with ID=1)
Models:
class Contact < ActiveRecord::Base
has_many :contact_sectors
has_many :sectors, through: :contact_sectors
accepts_nested_attributes_for :contact_sectors, :reject_if => :all_blank, :allow_destroy => true
accepts_nested_attributes_for :sectors, :reject_if => :all_blank, :allow_destroy => true
end
class Sector < ActiveRecord::Base
has_many :contact_sectors
has_many :contacts, through: :contact_sectors
def name_with_initial
"#{sector}"
end
end
class ContactSector < ActiveRecord::Base
belongs_to :contact
belongs_to :sector
end
View:
<%= f.fields_for(:sectors) do |s| %>
<%= s.collection_check_boxes :id, Sector.all,
:id, :name_with_initial,
{ prompt: true }, { class: 'form-control' } %>
<% end %>
Controller
def edit
#contact.sectors.build
end
def contact_params
#Not sure if I need something like this or not
params['contact']['sectors'] = params['contact']['sectors']['id'].split(',')
params.require(:contact).permit(:firstname, :lastname,
contact_sectors_attributes: [:id],
sectors_attributes: [:_destroy, {:id => []}])
end
Instead of creating the join model explicitly you can just declare the relationship as has_many through: and let ActiveRecord handle the join model:
class Contact < ActiveRecord::Base
has_many :contact_sectors
has_many :sectors, through: :contact_sectors
accepts_nested_attributes_for :sector,
reject_if: :all_blank, allow_destroy: true
end
class Sector < ActiveRecord::Base
has_many :contact_sectors
has_many :contacts, through: :contact_sectors
end
class ContactSector < ActiveRecord::Base
belongs_to :contact
belongs_to :sector
end
<%= form_for(#contact) do |f| %>
<%= f.fields_for(:sectors) do |s| %>
<%= s.collection_check_boxes :id, Sector.all,
:id, :name_with_initial,
{ prompt: true }, { class: 'form-control' } %>
<% end %>
<% end %>
models
class Contact < ActiveRecord::Base
has_many :sectors, through: :contact_sectors
has_many :contact_sectors
accepts_nested_attributes_for :sectors
end
class Sector < ActiveRecord::Base
has_many :contacts, :through => :contact_sectors
has_many :contact_sectors
end
class ContactSector < ActiveRecord::Base
belongs_to :contact
belongs_to :sector
end
view
<%= form_for(#contact) do |f| %>
<% Sector.all.each do |sector| %>
<%= check_box_tag "contact[sector_ids][]", sector.id, f.object.sectors.include?(sector) %>
<%= sector.sector %>
<% end %>
<% end %>
controller
def update
#To make sure it updates when no boxes are ticked
#contact.attributes = {'sector_ids' => []}.merge(params[:contact] || {})
end
def contact_params
params.require(:contact).permit(:firstname, :lastname, sector_ids: [])
end
Recommended reading:
http://millarian.com/rails/quick-tip-has_many-through-checkboxes/
Rails 4 Form: has_many through: checkboxes

accepts_nested_attributes_for with belongs_to polymorphic devise

I have 3 models and this associations for them
class User < ActiveRecord::Base
# devise modules here
attr_accessible :email, :password, :password_confirmation, :remember_me, :rolable_id, :rolable_type
belongs_to :rolable, :polymorphic => true
end
class Player < ActiveRecord::Base
attr_accessible :age, :name, :position
has_one :user, :as => :rolable
end
class Manager < ActiveRecord::Base
attr_accessible :age, :name
has_one :user, :as => :rolable
end
I'm out of the box from rails way to put accepts_nested_attributes_for :rolable on user model and In this accepts_nested_attributes_for with belongs_to polymorphic question I found some solutions for it but all solution not works for me. All solutions, always the same error when I try to create a user
Processing by RegistrationsController#create as HTML
Parameters: {"utf8"=>"V", "authenticity_token"=>"WKCniJza+PS5umMWCqvxFCZaRVQMPZBT4nU2fl994cU=", "user"=>{"email"=>"john#email.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "rolable_type"=>"manager", "rolable"=>{"name"=>"john", "age"=>"24"}}, "commit"=>"Sign up"}
Completed 500 Internal Server Error in 143.0ms
NoMethodError (undefined method `primary_key' for ActiveSupport::HashWithIndifferentAccess:Class):
app/controllers/registrations_controller.rb:13:in `new'
app/controllers/registrations_controller.rb:13:in `create'
My mistake, I'm use nested form
<%= f.fields_for :rolable do |rf| %>
....
<% end %>
change to
<%= f.fields_for :rolable_attributes do |rf| %>
....
<% end %>
for polymorphic association you have to maintain generic model Roll like
class User < ActiveRecord::Base
# devise modules here
attr_accessible :email, :password, :password_confirmation, :remember_me
has_many :rolls, :as => :rolable
end
class Player < ActiveRecord::Base
attr_accessible :age, :name, :position
has_many :rolls, :as => :rolable
end
class Manager < ActiveRecord::Base
attr_accessible :age, :name
has_many :rolls, :as => :rolable
end
class Roll < ActiveRecord::Base
attr_accessible :rolable_id, :rolable_type
belongs_to :rolable, :polymorphic=> true
end

Attributes not showing on users#show page

users_controller.rb
class ProfilesController < ApplicationController
before_filter :authenticate_user!
def show
#user = User.find(params[:id]) || User.find(current_user.id)
#questions_for_about = #user.questions.for_about.order('id asc')
#questions_for_personality = #user.questions.for_personality.order('id asc')
end
end
user#show.html.erb
<div class="element">
Ethinicity:
<%= #user.ethnicity.present? ? #user.ethnicity.name : "" %>
</div>
<div class="element">
Education:
<span class="select_for_education">
<%= #user.education.present? ? #user.education.name : "" %>
</div>
The user.education.name is just showing the following - Education:
Without showing the users Education in which was chosen on his personal profile using the following select:
<div class="element">
Ethinicity:
<%= best_in_place current_user, :ethnicity_id, :type => :select, collection: Ethnicity.all.map{|e| [e.id, e.name]}, :inner_class => 'education-edit', nil: 'Select Ethnicity' %>
</div>
<div class="element">
Education:
<span class="select_for_education">
<%= best_in_place current_user, :education_id, :type => :select, collection: Education.all.map{|e| [e.id, e.name]}, :inner_class => 'education-edit', nil: 'Select Education' %>
</div>
What am I doing wrong? And how can I get the users education that DOES display on his/her own profile to display in the show page?
Thanks in advanced!
User.rb
class User < ActiveRecord::Base
include PgSearch
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable,
:omniauth_providers => [:facebook, :twitter, :linkedin]
attr_accessible :email, :password, :password_confirmation, :zip, :gender, :remember_me, :first_name, :last_name,
:birthday, :current_password, :occupation, :address, :interests, :aboutme, :profile_image,
:photos_attributes, :age, :education_id, :ethnicity_id, :blurb
has_many :authorizations, :dependent => :destroy
has_many :comments
has_many :events
has_many :photos, as: :attachable
has_many :questions
has_many :sent_messages, class_name: 'Message', foreign_key: :sender_id
has_many :received_messages, class_name: 'Message', foreign_key: :receiver_id
has_one :ethnicity
has_one :education
end
ethnicity.rb
class Ethinicity < ActiveRecord::Base
attr_accessible :name
has_many :users
end
education.rb
class Education < ActiveRecord::Base
attr_accessible :name
has_many :users
end
You're missing belongs_to association for has_many and has_one relation. The belongs_to association definition needs to be defined in the model whose table has the foreign key.
Given your models, although the other way around is imaginable, here is what I think the associations should look like:
# User Model
class User < ActiveRecord::Base
...
belongs_to :ethnicity
belongs_to :education
end
# Ethnicity Model
class Ethinicity < ActiveRecord::Base
attr_accessible :name
has_many :users
end
# Education Model
class Education < ActiveRecord::Base
attr_accessible :name
has_many :users
end

How to update attributes in many to many relation in rails?

I am new in rails. So i am not comprehending much of it. I have a database with three table. students table, courses table and registrations table.
My Railde models are as follows :
class Student < ActiveRecord::Base
attr_accessible :name
has_many :registrations
has_many :courses, :through => :registrations
validates :name, :presence => true
end
class Course < ActiveRecord::Base
attr_accessible :name
has_many :registrations, :dependent => :destroy
has_many :students, :through => :registrations
validates :name , :presence => true
validates :name, :uniqueness => true
end
class Registration < ActiveRecord::Base
attr_accessible :course_id, :student_id
belongs_to :course
belongs_to :student
validates :course_id, :student_id, :presence => true
validates :course_id, :uniqueness => {:scope => :student_id}
validates :student_id, :uniqueness => {:scope => :course_id}
end
......................
Controller action for updating student :
def update
#student = Student.find(params[:id])
if #student.update_attributes(params[:student])
redirect_to students_path, :notice => "Registration completed"
else
render 'edit'
end
end
................
View :
<%=form_for #student do |f| %>
<p>
<%= f.label :name, "Name" %>
<%= f.text_field :name %>
</p>
<p>
<%= render('course_list') %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
...............
_course_list partial :
Select Courses :<br/>
<p>
<% Course.all.each do |course| %>
<%=check_box_tag "student[course_ids][]", course.id, `enter code here`#student.course_ids.include?(course.id) %>
<%= course.name %> <br/>
<% end %>
</p>
.............................
when i submit the update button, i got an error
Can't mass-assign protected attributes: course_ids
.......
parameters :
{"utf8"=>"✓",
"_method"=>"put",
"authenticity_token"=>"j/lDE5bv1gWkfadQ6Cag6hGjg5nD2Ikad9vHOJTE7Pc=",
"student"=>{"name"=>"Galib",
"course_ids"=>["2",
"3"]},
"commit"=>"Update Student",
"id"=>"6"}
.........................
What i want to do is, if update button is clicked, both students table and registrations table need to be updated. Please help.
In models define the associations
class Student < ActiveRecord::Base
attr_accessible :name
has_many :registrations
has_many :courses, :through => :registrations
validates :name, :presence => true
accepts_nested_attributes_for :courses
attr_accessible :course_ids
end
class Course < ActiveRecord::Base
attr_accessible :name
has_many :registrations, :dependent => :destroy
has_many :students, :through => :registrations
validates :name , :presence => true
validates :name, :uniqueness => true
accepts_nested_attributes_for :students
end
class Registration < ActiveRecord::Base
attr_accessible :course_id, :student_id
belongs_to :course
belongs_to :student
validates :course_id, :student_id, :presence => true
validates :course_id, :uniqueness => {:scope => :student_id}
validates :student_id, :uniqueness => {:scope => :course_id}
accepts_nested_attributes_for :course
end
In Controller
def update
#student = Student.find(params[:id])
if #student.update_attributes(params[:student])
#student.courses.build
redirect_to students_path, :notice => "Registration completed"
else
render 'edit'
end
end
It may help you
The error is telling you that you have a permission error - course_ids can't be posted to from a form. More specifically, you have attr_accessible :name in the Student model which means that is the only attribute that can be saved when you save a Student record using a form (attr_accessible dictates what can be mass assigned).
Try changing your Student model to:
attr_accessible :name, :registrations_attributes
accepts_nested_attributes_for :registrations
You are trying to created a nested model form, so accepts_nested_attributes_for is used for this.
If you want to have the Registrations table updated, as well, you're going to have to tell the partial so that it knows that the partial is updating a different model than Student.
<%= f.fields_for :registrations do |registration| %>
<%= render('course_list') %>
<% end %>
In case of MongoDB, For implementing many to many in rails model you have to use has_and_belongs_to_many instead of simple has_many

Resources