Form control-group for rails polymorphic association - ruby-on-rails

In my rails app I have following models:
class Book < ApplicationRecord
belongs_to :bookable, polymorphic: true
end
class Student < ApplicationRecord
has_many :books, as: :bookable
end
class Library < ApplicationRecord
has_many :books, as: :bookable
end
When creating a new book object in form.html.erb, how I could map t.integer :bookable_id and t.string :bookable_type to specific object?
Ideally I would use grouped_collection_select and pull first Student and Library and below their ids.
Thanks in advance.

When creating a new book object in form.html.erb, how I could map
t.integer :bookable_id and t.string :bookable_type to specific object?
Well, you can use the collection_select or grouped_collection_select (according to your requirements) to display Students and Libraries to store the values for bookable_id.
For bookable_type, Rails under the hood reads the class names of the instances and captures the class name and stores it as a value for bookable_type. For example, consider the below approach
#student = Student.find(1)
#student.books.create
The above code snippet will create a record in books table with bookable_id = 1 and bookable_type = "Student"

Related

Passing a child to container of parent type

I have a parent class Individual and child classes Student and Professor in my rails application.
Inheritance is handled with a gem called 'acts_as_relation' which simulates multiple table inheritance.
In addition, I have an action within which a student instance is appended to a list of individuals. Normally I would have expected this to go through without any problems but I get this error:
ActiveRecord::AssociationTypeMismatch: Individual(#70220161296060) expected, got Student(#70220161349360)
Here is a glance at my model:
class Individual < ActiveRecord::Base
acts_as_superclass
end
class Student < ActiveRecord::Base
acts_as :individual
end
class Professor < ActiveRecord::Base
acts_as :individual
end
I've not used this gem, but to give you some help, here's what I've found and this:
They both mention that you're calling an object through your relation, which will have confusion over polymorphism or similar. The two posts could not fix the issue, and I presume that is because they could find the correct object for their relationship
Looking at this further, I found this tutorial on the gem homepage:
acts_as_relation uses a polymorphic has_one association to simulate
multiple-table inheritance. For the e-commerce example you would
declare the product as a supermodel and all types of it as acts_as
:product (if you prefer you can use their aliases is_a and
is_a_superclass)
class Product < ActiveRecord::Base
acts_as_superclass
end
class Pen < ActiveRecord::Base
acts_as :product
end
class Book < ActiveRecord::Base
acts_as :product
end
To make this work, you need to declare both a foreign key column and a
type column in the model that declares superclass. To do this you can
set :as_relation_superclass option to true on products create_table
(or pass it name of the association):
create_table :products, :as_relation_superclass => true do |t|
# ...
end
Or declare them as you do on a polymorphic belongs_to association, it
this case you must pass name to acts_as in :as option:
change_table :products do |t|
t.integer :producible_id
t.string :producible_type
end
class Pen < ActiveRecord::Base
acts_as :product, :as => :producible
end
class Book < ActiveRecord::Base
acts_as :product, :as => :producible
end
Are you sure you've got your datatables set up correctly?
The way I've solve this in my projects, is using instance_ofsome_class.individuals << student_instance.individual.
The thing here is that is not a real MTI, so your collection of individuals would accept only individuals instances. If you call some_student_instance.individual or some_professor_instance.individual, you'll get an individual instance which is related with your specific instance.
Then working with that collection, if you want a Student or Professor all you need to do is call individual_in_collection.specific. For example:
p = Professor.create
a_model.individuals << p.individual
puts "#{a_model.individuals.first.class.name}"
=> Individual
puts "#{a_model.individuals.first.specific.class.name}"
=> Professor

What is the process of creating a joining table which resolves a many-to-many relationship using migrations?

I would like to understand the process which can be followed to create models and migrations which in turn create a joining table within the database to resolve a many-to-many relationship. For instance. If i have a course table, a students table and i want to create a joining table called studies with the id from course and students along with extra data such as the grade and date started. Exactly What is the process for doing this?
If i am to use the generate model command for each of the above 3 table names, this will create a separate migration for all of them. Even if i go into the models and add the relevant associations this will not affect how the database is created? Please could you give me some guidance on what steps i must take in order to create the required foreign key relationships here with some examples?
Use a has_many :through association. Set it up manually.
Step 1: Generate your models separately. The joining model Study will contain foreign keys, so remember to include the columns.
rails g model Course title:string
rails g model Student name:string
rails g model Study course_id:integer student_id:integer start_date:date grade:string
Step 2: Set up associations:
# models/course.rb
class Course
has_many :studies
has_many :students, through: :studies
end
# models/student.rb
class Student
has_many :studies
has_many :courses, through: :studies
end
# models/study.rb
class Study
belongs_to :course
belongs_to :student
end
Step 3: Run migrations, restart server (if necessary), and that's it. Rails will handle the rest.
Accessing attributes in the joining table may require careful timing to ensure the correct object is being accessed, since the joining object is not returned via Rails' built-in methods, ie #course.students. Check out this answer for some ideas.
Read the guide for more information.
for many-to-many relationships use:
class Car < ActiveRecord::Base
has_and_belongs_to_many :tires
end
class Tire < ActiveRecord::Base
has_and_belongs_to_many :cars
end
Then you create a migration like this:
class CreateCarsAndTires < ActiveRecord::Migration
def change
create_table :cars do |t|
t.string :name
end
create_table :tires do |t|
t.string :something
end
create_table :cars_tires do |t|
t.belongs_to :car
t.belongs_to :tire
t.string :additional_dataA //optional
t.int :something_else //optional
end
end
end
It is very important that you name your join table in the migration in alphabetical order (c in cars comes before t for tires) as ActiveRecord will look in has_many_and_belongs_to relations for a table which is named this way pluralized-classA_pluralized_classB like apples_bananas vs bananas_apples which would not work and you would have to add the table name to your classes and it goes against the convention over configuration paradigm.
Hope it helps.

Using Dropdown menu for One to One relationship

I plan on making a genotype calculator in the future. I intend for this calculator to eventually be able to compute the following from a pairing: probability of color listing all possibilities, genotype.
I am wanting to make a dropdown menu/text field combination on a very simple webpage to learn how it works so that I can continue my project and hopefully meet this goal. I have searched and tried to figure this out, but I am pretty lost. Currently in my database I have a table called "colors" with the following schema:
id
angora_color
genotype
created_at
updated_at
I do not intend for users to be able to add data to this form. I want them to be able to select a color from the dropdown box, and get the genotype in a text field below it.
My code so far is as follows:
class Color < ActiveRecord::Base
has_one :genotype
end
class Genotype < ActiveRecord::Base
has_one :color
end
index.html.erb:
<h2>Placeholder for Genotype List..</h2>
class PagesController < ApplicationController
def index
end
end
I appreciate any help.
Are you sure you only want a has_one relationship? Wouldn't a Genotype have many colors? and Colors can be part of many Genotypes?
You also can't have both models declare has_one. One model has to belong to the other. And the one that belongs_to should have the foreign key as <model_name>_id e.g. genotype_id. In your table you only put genotype. Rails looks for that _id.
What may be better here is to use has_many through. Create a join model such as genotypes_colors:
rails g model GenotypesColor genotype_id:integer color_id:integer
Then change your code to look like:
class Genotype < ActiveRecord::Base
has_many :genotypes_colors
has_many :colors, through: :genotypes_colors
end
class GenotypesColor < ActiveRecord::Base
belongs_to :genotype
belongs_to :color
end
class Color < ActiveRecord::Base
has_many :genotypes_colors
has_many :genotypes, through: :genotypes_colors
end
Now you can correctly relate a Genotype to its Colors. You can use fields_for in either model's forms to create the genotypes_color association that will relate a Genotype to any Color or vice versa. If this sounds about right let me know and I can further help on how to do the forms.
Right now my migration reads as follows:
class CreateColors < ActiveRecord::Migration
def change
create_table :colors do |t|
t.string :angora_color
t.string :genotype
t.timestamps
end
end
end

Rails: polymorphic assoziation, has_many :through

Im not sure i understand rails polymorphic.
In Java you can create Objects from the same Objecttype:
http://www.fh-kl.de/~guenter.biehl/lehrgebiete/java2/j2-08-Dateien/abb.8.10.jpg
Person trainer = new Trainer()
Person sportler = new Trainer()
In Rails http://guides.rubyonrails.org/association_basics.html#polymorphic-associations:
In this example: picture can be from an employee or from a product, sounds strange because this is not realy the same type.
Do i understand the real purpose: to save objects in the same container an array of person or image?
In my rails project: I have several person: sportsmen, trainer and guest. They are sons of person (inheritance).
I think i meet the inheritance reason.
There is another class named exercise.
Sportsmen and trainer can create exercises.
So i want to use polymorphic. Exercises can be from trainer or sportsmen. Like in the example of the rails page, images can be from employee or a product.
Do i meet the best practise?
How do i implement a has_many :through with polymorphy?
It is not possible to use a habtm assoziation with polymorphic.
You have to define a additional class, but how exactly?
I think you want single table inheritance (STI) models, not a polymorphic relationship.
See this article http://www.alexreisner.com/code/single-table-inheritance-in-rails and these stackoverflow answers Rails - Single Table Inheritance or not for Applicant/Employee relationship Alternative to Rails Single Table Inheritance (STI)?
Just to make it clear, you should use polymorphic associations when you have a model that may belong to many different models on a single association.
Suppose, you want to be able to write comments for users and stories. You want both models to be commendable. Here's how this could be declared:
class Comment < ApplicationRecord
belongs_to :commentable, polymorphic: true
end
class Employee < ApplicationRecord
has_many :comment, as: :commentable
end
class Product < ApplicationRecord
has_many :comment, as: :commentable
end
To declare the polymorphic interface (commendable) you need to declare both a foreign key column and a type column in the model.
class CreateComments < ActiveRecord::Migration
def change
create_table :comments do |t|
t.text :body
t.integer :commentable_id
t.string :commentable_type
t.timestamps
end
add_index :comments, :commentable_id
end
end
You can check more details about associations here.

Class inheritance in Ruby on Rails

I'm building this little app with ruby on rails.
In the app, I'm having the following models strutter which I'm not sure whether it's the best ror practice. (I'm actually a Java developer)
There is a person class which I use it as a super class, and there are staff class and customer classes inherits from the person class. To achieve this, I have:
class Person < ActiveRecord::Base
end
class Staff < ActiveRecord::Base
belongs_to :person, :polymorphic => true, :dependent => :destroy
end
class CreateStaffs < ActiveRecord::Migration
def self.up
create_table :staffs do |t|
t.references :person, :polymorphic => true, :null => false
....
Firstly, what I did works fine, but am i doing the best thing?
The next thing I'm trying to do is to create a form which creates person, staff objects and link them. And I'm stuck on having two models on a single form.
Does anyone have suggestions?
Thanks,
Kevin Ren
What you're doing here is not to use Person as a superclass of Staff, but you create a relation between them. You want to look at single-table inheritance instead. You essentially want this:
class Person < ActiveRecord::Base
end
Class Staff < Person
end
In addition you need to have a "type" field in your Person table that Rails uses to figure out which model a given record belongs to. See the docs for ActiveRecord for more info.

Resources