How to add a new attribute to Associate Table column in rails - mysql

In my rails application, I had to add a new column named is_leader for an association table.
The relationship for the association table is as follows:
has_and_belongs_to_many :analysis_responses, :join_table => "analysis_responses_participants"
Following is the code where the participant details have been saved to the db:
organization.people.create(participant)
the participant has got the following values
name: Test User
position:
birthdate:
id:
lead: "1"
If the lead value is 1, the is_leader column value should be 1 for the particular record.
I wanted to know how can I save the is_leader value in that association table in rails
Thanks

If you need to save attributes on the join table, then you will have to use a join model instead of a HABTM.
class Organization
has_many :analysis_responses
has_many :people, through: :analysis_responses
end
class AnalysisResponse
belongs_to :organization
belongs_to :person
end
class Person
has_many :analysis_responses
has_many :organizations, through: :analysis_reponses
end

Related

How to make associations on this

Hello, i'm new to rails. I have been fed up with active record associations. I did study associations from the rails guides. Yet i cant find myself a clear way to add associations to the models suggested in the diagram.
I have one doubt whether a single foreign key(SECOND MODEL) can reference two primary keys (SECOND MODEL LEVEL 2 FIRST & SECOND MODEL LEVEL 2 SECOND). This has been done because the user has to choose whether to add from the SECOND MODEL LEVEL 2 FIRST TABLE or the SECOND MODEL LEVEL 2 SECOND TABLE while inserting values into the SECOND MODEL.
If u find this hard to understand please leave a comment, ill make appropriate changes. And i would appreciate on how to query from the FINAL LEVEL FIRST with BASE-MODEL thorough a join condition.
You can use polymorphic association to refer to one table OR another, check the model below as per the posted image:
class BaseModel
has_many :first_models
has_many :second_models
end
class FirstModel
belgons_to :base_model
has_one :level_two_first_model
end
class LevelTwoFirstModel
belgons_to :first_model
end
class SecondModel
belgons_to :base_model
has_many :final_first_levels, as: :referenceable, :dependent => :destroy
has_many :final_second_levels, as: :referenceable, :dependent => :destroy
end
class LevelOneSecondModel
belongs_to :referenceable, polymorphic: true
has_many :final_first_levels
end
class LevelTwoSecondModel
belongs_to :referenceable, polymorphic: true
has_many :final_first_levels
end
class FinalFirstLevel
belongs_to :LevelOneSecondModel
end
class FinalSecondLevel
belongs_to :LevelTwoSecondModel
end
referenceable is used as the glue between the parent table and other polymorphic associations (LevelOneSecondModel OR LevelTwoSecondModel)
NB:
Don't forget to add the below line in the migration files of the 2 children tables used in polymorphic association.
t.references :referenceable, polymorphic: true, index: true
Reference:
http://guides.rubyonrails.org/association_basics.html#polymorphic-associations

Rails Active Record: How to join three tables?

I've three tables as shown below:
Advertiser model:
class Advertiser < ActiveRecord::Base
has_many :advertisers_account_groups
AdvertisersAccountGroup model
class AdvertisersAccountGroup < ActiveRecord::Base
belongs_to :advertiser
belongs_to :v2_account_account_group, class_name: 'V2Account::AccountGroup', foreign_key: 'account_group_id'
I wanna know which advertiser belongs to v2_account_account_groups
and wanna get v2_account_account_groups.name
Desired Output:
What I tried;
Advertiser.where(media_type: "line").joins(advertisers_account_groups,v2_account_account_groups)
But it doesn't work
It looks to me that your current setup uses AdvertisersAccountGroup as a join table; therefore, I'd suggest using a has_many :through association.
To do this, you'd just need to switch up the models as follows:
class Advertiser < ActiveRecord::Base
has_many :v2_account_account_groups, through: :advertisers_account_groups
has_many :advertisers_account_groups
...
end
class V2Account::AccountGroup < ActiveRecord::Base
has_many :advertisers, through: :advertisers_account_groups
has_many :advertisers_account_groups
...
end
class AdvertisersAccountGroup < ActiveRecord::Base
belongs_to :advertiser
belongs_to :v2_account_account_group, class_name: 'V2Account::AccountGroup', foreign_key: 'account_group_id'
...
end
This will allow you to query against the advertiser as desired, i.e. advertiser.v2_account_account_groups.
However, this association is a many-to-many between advertisers and v2 account groups as is - therefore, you won't be able to call advertiser.v2_account_account_groups.name as advertiser.v2_account_account_groups returns a collection rather than a single record.
You could use advertiser.v2_account_account_groups.map(&:name) (to get an array of all groups' names) or advertiser.v2_account_account_groups.first&.name, but it sounds as if you might need to restructure the data if an advertiser should have just the one v2 account group.
Does that make sense and sound like what you're looking for? Let me know if you've any questions.
Edit:
Based on your comment, I think you should be able to construct a query as follows:
Advertiser.includes(advertiser_account_groups: : v2_account_account_group)
.where(advertiser_account_groups: { v2_account_groups: { name: "something" } })
Does that sound like what you're looking for?
A couple of things to note:
when referencing the associations in the includes, you want to use the association name
however, when plugging these into the where clause, you need to use the full table names, as they are in the databases (searchable via Model.table_name)
Also, in your comment, you reference adding media_type: "line", which the below also includes:
Advertiser.includes(advertiser_account_groups: : v2_account_account_group)
.where(media_type: "line", advertiser_account_groups: { v2_account_account_groups: { name: "something" } })
Probably the best way to structure this in your code is as a scope in your advertiser model, such as:
scope :by_v2_group_name, -> (name) { includes(advertiser_account_groups: :v2_account_account_group)
.where(media_type: "line", advertiser_account_groups: { v2_account_account_groups: { name: "something" } }) }
or
scope :by_v2_group_name, (lambda do |name|
includes(advertiser_account_groups: :v2_account_account_group)
.where(media_type: "line", advertiser_account_groups: { v2_account_account_groups: { name: "something" } })
end)
That will then allow you to keep your code clean and call Advertiser.by_v2_group_name("something").
Let me know how you get on with that and we'll work on it as needed :)
This answer is relevant only if you don't need a model for the join table
advertiser_account_gourps
(if you don't have any extra attributes other then advertiser_id and account_gourp_id on that join table - you usually don't need it)
While #SRack's answer is using the has_many :through association, I think you can use a simple many-to-many association (has_and_belongs_to_many) because in your images i can see that the join table only have the ids of the associated tables (Unless you do need the id column -> and in that case, use #SRack's solution!)
class Advertiser < ActiveRecord::Base
has_and_belongs_to_many :advertisers_account_groups
class AccountGroup < ActiveRecord::Base
has_and_belongs_to_many :advertisers
then you can get them using:
advertiser = Advertiser.first
advertiser.account_groups #to get account groups of that advertiser
and vice versa:
account_group = AccountGroup.first
account_group.advertisers # to get advertisers of that account group
#SRack's comment is correct! i changed it to HABTM association!
In that case you will need to create a migration to make the join table:
rails g migration CreateJoinTableAdvertiserAccountGroup advertiser account_group
This table will only include the associated advertiser_id and the account_group_id.
You don't need to create a model and handle stuff on that table, rails will fill that table for you.

RAILS ActiveRecord::Relation how to get many-to-many though: table name

I am in my quest of overriding activerecord method, but I need to be access the table name many-to-many relationship :through . How do i do it?
For example I have model Student and Subject, to connect the two I use has_many Subjects, through: :registers.
I have a statement Student.find(1).subjects, how do i get the table name register from the activerecord statement?
Thanks
Student.rb
Class Student < ActiveRecord::Base
has_many :registers
has_many :subjects, :through => :registers
end
subject.rb
class Subject < ActiveRecord::Base
has_many :registers
has_many :students, :through => :registers
end
register.rb
Class Register
belongs_to :student
belongs_to :subjet
end
Make sure your associations added like this. And You can get your all subject lists by Student.find(1).subjects
And You can also check entries in Register table by using Register.all
You can access all the register records like below.
Register.all
From your statement "Student.find(1).subjects", if you wish to get the registers along with the subjects details, you can do as:
Student.find(1).subjects.select("subjects.name, registers.name")

Rails association - Customised list of items from existing list

I am developing a rails app where users can add tasks they wish to do to a customised list of their own. Each task can also belong to 0 or more categories. So far I've tried this:
user.rb
has_one :user_list
has_many :tasks, through: :user_list
user_list.rb
belongs_to :user
has_many :tasks
tasks.rb
has_and_belongs_to_many :categories
[timestamp}_migration.rb
create_table :user_lists do |t|
t.integer :user_id
t.integer :task_id
t.timestamps null: false
end
The issue I am having is in the console I try to run User.find(1).tasks it cannot find the column tasks.user_list_id when using the following query:
SELECT "tasks".* FROM "tasks" INNER JOIN "user_lists" ON "tasks"."user_list_id" = "user_lists"."id" WHERE "user_lists"."user_id" = ? [["user_id", 1]]
This query should be joining the tasks id from the tasks table with the tasks id on the user_lists table. Are the associations correct and if so what can I do to change the query?
To allow tasks to be placed on many lists you need a M2M join table which joins the user_lists and tasks table.
class User < ActiveRecord::Base
has_many :user_lists
has_many :tasks, through: :user_lists
end
class Task < ActiveRecord::Base
has_many :user_list_items
has_many :user_lists, through: :user_list_items
end
class UserListItem < ActiveRecord::Base
belongs_to :task
belongs_to :user_list
has_one :user, through: :user_list
# optional
validates_uniqueness_of :task_id, scope: :user_list_id
end
class UserList < ActiveRecord::Base
belongs_to :user
has_many :user_list_items
has_many :tasks, through: :user_list_items
end
You can create the join model and migration with:
rails g model UserListItem user_list:belongs_to task:belongs_to
You may also want to open up the migration and add a compound index:
add_index :user_list_items, [:user_list_id, :task_id], unique: true
Setting it as unique is optional - but in most cases you want join table entries to be unique for table A and B.
See:
http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
http://guides.rubyonrails.org/active_record_migrations.html
Your use case calls for a task to be assigned to more than one user and a user has only one task list. This sounds like a HABM association between users and tasks.
The simplest way to express that would be:
class User
has_and_belongs_to_many: :tasks
...
end
class Task
has_and_belongs_to_many: :users
...
end
and a migration to create the join table:
create_join_table :users, :tasks, do |t|
t.index :user_id
t.index.task_id
end
You don't need to create a TaskUser model to match the join table until you need to track additional attributes. Rails will take care of that automatically.
If a user needs more than one task list, you'll need that TaskList model. Let me know and I'll update my answer.
Here's the documentation on HABM and join migration

Storing Location Data in the Database

I need to store data about specific Objects which include information about Location(Country, City, District) of an object. I'm trying to figure out the best way to store described above location data in the MySQL database and how it should look like in the rails active model.
My dummy idea is to create 3 separate tables like below:
Location_countries
id
name
Location_cities
id
country_id
name
Location_districts
id
city_id
name
Create a separate table for an object and call it the item_location and include Ids of object its country... so on
Next is to create 3 Rails models (Country, City, Districts).. , but I think it's a very dirty way and it can be combined into the single Model like Item_location
Any Ideas?
Thank you in advance!
I don't entirely understand what you're looking to do, but either way, here's how I'd tackle it:
#app/models/object.rb
Class Object < ActiveRecord::Base
has_one :location
end
#app/models/location.rb
Class Location < ActiveRecord::Base
belongs_to :object
belongs_to :city
belongs_to :district
delegate :name, to: :city, prefix: true
delegate :name, to: :district, prefix: true
end
#app/models/city.rb
Class City < ActiveRecord::Base
has_many :locations
belongs_to :country
end
#app/models/district.rb
Class District < ActiveRecord::Base
has_many :locations
end
#app/models/country.rb
Class Country < ActiveRecord::Base
has_many :cities
end
This will give you the ability to call:
#object = Object.find params[:id]
#object.location.city_name
#object.location.district_name