collection_select with has_many :through relationship table data - ruby-on-rails

I have such terrible models:
class ParentalRelation < ActiveRecord::Base
belongs_to :parent
belongs_to :student
belongs_to :counselor
belongs_to :parental_relation_type
end
class ParentalRelationType < ActiveRecord::Base
has_many :parental_relations
end
class Parent < ActiveRecord::Base
has_many :parental_relations
has_many :students, :through => :parental_relations
has_many :counselors, :through=> :parental_relations
has_many :parental_relation_types, :through=> :parental_relations
belongs_to :user, :dependent=> :destroy
belongs_to :occupation_type
accepts_nested_attributes_for :user
end
Parental relation types are like father, mother, etc. The reasoning is that a parental relation between one counselor, one parent and one student is unique and counselors should not see the relations that belong other counselors.
In controllers/parent_controller/edit action I have:
#parental_relation= ParentalRelation.find_by_counselor_id_and_student_id_and_parent_id(x, y, z)
In views/parent/_form.html.erb I have:
<%= form_for #parent do |f| %>
inside that form I need a collection_select for ParentalRelationType.all and select the parent's parental_relation_type_id for that particular parental relation, but I can't find the syntax to do it.
I tried adding
<%= collection_select(#parental_relation, :parental_relation_type_id, ParentalRelationType.all, :id, :name) %>
underneath the form_for, but the relation type id is 2, and default 1 is selected instead.

Added this to parents/_form
<%= fields_for #counselor_student_parent do |csp| %>
<%= f.label :parental_relation_type_id %>
<%= collection_select(:student_counselor_parent, :parental_relation_type_id, ParentalRelationType.all, :id, :name) %>
<% end %>
And this to parents_controller/new
def new
#counselor= Counselor.find(params[:counselor_id])
#student= Student.find(params[:student_id])
#parent= #student.parents.build
#parent_user= #parent.build_user
#counselor_student_parent= #counselor.student_counselor_parents.build
end

Related

Setting limitations across has_many through models

Those are my models:
class User < ActiveRecord::Base
has_many :memberships
has_many :groups, through: :memberships
end
class Group < ActiveRecord::Base
has_many : memberships
has_many :users, through: :memberships
belongs_to :group_type
end
class Membership < ActiveRecord::Base
belongs_to :user
belongs_to :group
end
class GroupType < ActiveRecord::Base
has_many :groups
end
I would like to assign groups to users. there are several types of groups, users can choose only one group from each type. in the view there should a select tag for each group type (a user don't have to be a member of each of the group types).
I can add a type_id column to the membership model and create a instance for each group for each new user, and then update rows, with something like (for type 1):
<%= form_for (#user) do |f|
<% #membership = Membership.where (user_id: :#user.id, group_type: :1) %>
<%= f.collection_select (:membership, :group_id, Group.all.where(type: 1), :id, :name) %>
<% end %>
(not sure that it will work)
anyway I'm sure there is a better way.. how can I connect the models with the one group for each type limitation? (with, ofcourse, a way to edit existing memberships).
I would appriciate any assistance...
Thank you!
Your model structure look good. You could also include the group_type in the membership and than validate against uniqueness.
class Membership < ActiveRecord::Base
belongs_to :user
belongs_to :group
belongs_to :group_type
validates :user_id, uniqueness: { scope: [:group_id, :group_type_id],
message: "can only join one group of this type." }
end
The form should create a membership.
<%= form_for (Membership.new) do |f|
<%= f.hidden_field :user_id, value: #user.id %>
<%# your selection for a group %>
<% end %>
In the controller you have to load the group from the DB, than add the group_type_id to params and .save -> The validation will handle the rest.

save association in pivot table in rails 5

I have a common many to many relationship, these are the models:
class Employee < ApplicationRecord
has_many :related_professions
has_many :professions, through: :related_professions
accepts_nested_attributes_for :related_professions
end
class RelatedProfession < ApplicationRecord
belongs_to :employee
belongs_to :profession
accepts_nested_attributes_for :profession
end
class Profession < ApplicationRecord
has_many :related_professions
has_many :employees ,through: :related_professions
end
I also have a form for saving Employees. In this form I would like to render all the Professions in a multiple select for the user to choose as needed. I want that when the user submits the form, the IDs of all the selected professions be saved in the RelatedProfession pivot table (which just have three columns: id, employee_id, profession_id). This is the part of my form for the select:
<div class="field">
<%= form.label :professions %>
<%= form.fields_for :related_professions do |rp| %>
<%= rp.collection_select :profession_id, Profession.all, :id, :name, {}, {multiple: true} %>
<% end %>
</div>
And this is the part in my EmployeeController that allows the parameters:
# Never trust parameters from the scary internet, only allow the white list through.
def employee_params
params.require(:employee).permit(:name, related_professions_attributes: [:id, profession_id: [:id]])
end
The first problem is that the form does not load the Professions if the Employee does not have any assigned. I had to manually add one to the DB and then it would populate the select.
Second problem is that when I try to update the Employee (and also the RelatedProfession pivot table) by selecting a different Profession, it won't work, and I get this error:
Related professions profession must exist
I know there must be something wrong in the permit parameters and form that is not building the select correctly.
I appreciate the help. Thanks in advance.
You no need nested attributes to created has_many through relations,
You can just pass it as array of ids.
class Employee < ApplicationRecord
has_many :related_professions
has_many :professions, through: :related_professions
end
class RelatedProfession < ApplicationRecord
belongs_to :employee
belongs_to :profession
end
class Profession < ApplicationRecord
has_many :related_professions
has_many :employees ,through: :related_professions
end
In form also just select ids of Professions.
<div class="field">
<%= form.label :professions %>
<%= rp.collection_select :profession_ids, Profession.all, :id, :name, {}, {multiple: true} %>
</div>
change strong params to allow profession_ids as array.
def employee_params
params.require(:employee).permit(:name, profession_ids: [])
end
Hope this solves your problem.

How to create through relations based on enum in join table?

I would like to select in simple_form <%= f.association :organisators, collection: User.all %> and <%= f.association :helpers, collection: User.all %> that source of them will be User ids stored in Participation join table with appropriate enum kind, is it a way to do it automatically with ActiveRecord relations?
class Participation < ActiveRecord::Base
belongs_to :user
belongs_to :event
enum kind: [:helper, :organisator]
end
class Event < ActiveRecord::Base
belongs_to :user
has_many :participations
has_many :organisators, class_name: 'Participation'
has_many :helpers, class_name: 'Participation'
end
class User < ActiveRecord::Base
has_many :events
has_many :participations
end
When I try to save current version then it raise: Couldn't find Participation with 'id'=1
event_params: {"helper_ids"=>["2"], "organisator_ids"=>["1"]}
I would recommend using Single Table Inheritance over an enum. Keep the existing Participation model, and create two other models (helper and organiser) which will inherit from it.
Once you have implemented this, you can have two different object types which can be referenced through relationships while sharing one database model.
Take a look at this documentation:
http://api.rubyonrails.org/classes/ActiveRecord/Inheritance.html
source of them will be User ids stored in Participation join table
You need to pull from the Participation model, not the User model:
class Participation < ActiveRecord::Base
belongs_to :user
belongs_to :event
enum kind: [:helper, :organisator]
end
class Event < ActiveRecord::Base
belongs_to :user
has_many :participations
has_many :organisators, -> { where kind: :organisator}, class_name: 'User', through: :participations, source: :user
has_many :helpers, -> { where kind: :helper}, class_name: "User", through: :participations, source: :user
end
class User < ActiveRecord::Base
has_many :events
has_many :participations
has_many :participated_events, through: :participations
end
You've basically got a has_many :through relationship.
--
Thus, you should be able to use:
#app/views/events/update.html.erb
<%= simple_form_for #event do |f| %>
<%= f.association :organisators, collection: #event.organisators %>
<%= f.association :helpers, collection: #event.helpers %>
<%= f,submit %>
<% end %>
It would help if you gave some context on what you're trying to achieve. The above code should help, we may have to tweak it a little.

Show a name from associated class in ruby

I have Aulas and Students Through Grades,
in grades I want to display the name of the student and the name of the Aula.
<% #grades.each do |grade| %>
<%= grade.student.name %>
<%= grade.aula.name %>
<% end %>
If I leave only the student I get it perfect, But when I want to get Aula name, I get:
undefined method `aula' for #<#<Class:0x30a37e8>:0x2fffeb0>
Here is my code
class Aula < ActiveRecord::Base
attr_accessible :name
has_many :grades
has_many :students, :through => :grades
end
class Student < ActiveRecord::Base
attr_accessible :name
has_many :grades
has_many :aulas, :through => :grades
end
class Grade < ActiveRecord::Base
attr_accessible :grammar, :oral, :participation, :writing
belongs_to :aula
belongs_to :student
end
I figure that the problem is that if grade.aula.name is nil, I get this error. If the data is there, it works perfectly.
How can I do an action like, if grade.aula.name.nill? grade.aula.name = 'write the name here'?

Searching one model by another

My application consists of a drink model
class Drink < ActiveRecord::Base
attr_accessible :name
has_many :recipe_steps, :dependent => :destroy
has_many :ingredients, through: :recipe_steps
end
An ingredient model
class Ingredient < ActiveRecord::Base
attr_accessible :name
has_many :recipe_steps
end
how would I go about having it so when a user searches an ingredient that it returns all of the drinks with that ingredient?
Additional information: I'm currently using sunspot/solr for my searching.
First, in your Ingredient model you'd need this line:
has_many :drinks, through: :recipe_steps
To define the has_many, through: relationship. Make sure that RecipeStep has these lines, too:
belongs_to :ingredient
belongs_to :drink
Then you can do something like in the DrinksController:
def search
term = params[:search]
ingredient = Ingredient.where(:name => term)
#drinks = Ingredient.find(ingredient).drinks
end
And your form should look something like this:
<%= form_for #drink, :url => { :action => "search" } do |f| %>
<%= f.text_field :search %>
<% end %>
I don't know all your names for everything but this should get you going.
Following should work fine:
class Ingredient < ActiveRecord::Base
...
has_many :recipe_steps
has_many :drinks, through: :recipe_steps
end

Resources