How add association with custom FK in Ruby on Rails? - ruby-on-rails

I have two models: Users and Microposts. There is an association between one-to-many. I would like to add to Microposts field replic_to and replics_from to Users, and association with many-to-many relationships that will not only be stored in the model Microposts the author, but the user ID, which is addressed to the message. Because of already having associations between models, I think you need to specify the force field as FK for new association. I ask you to show how it can be done. Thank you in advance.
This`s sources:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.string :email
t.timestamps
end
end
end
class CreateMicroposts < ActiveRecord::Migration
def change
create_table :microposts do |t|
t.string :content
t.integer :user_id
t.timestamps
end
add_index(:microposts, [:user_id, :created_at]);
end
end
class User < ActiveRecord::Base
....
has_many(:microposts, dependent: :destroy);
....
end
class Micropost < ActiveRecord::Base
....
belongs_to :user;
....
end

Add to micropost.rb
belongs_to :replics_to, class_name: 'User'
The corresponding field should be
add_column :microposts, :replics_to_id, :integer
For user.rb
has_many :replics_from, class_name: 'User', foreign_key: 'replics_to_id'

Related

rails - can't save data in associated models in RoR

I have 2 Models with association has_many along with cascade property between them.
class ServicesBrandDetail < ApplicationRecord
has_many :services_brands, foreign_key: "brand_id", dependent: :delete_all
end
class ServicesBrand < ApplicationRecord
belongs_to :services_brand_details, foreign_key: "brand_id",
end
Migration for both files
class CreateServicesBrandDetails < ActiveRecord::Migration[6.1]
def change
create_table :services_brand_details do |t|
t.string :brand
t.string :mail_list
t.string :cc_list
t.timestamps
end
end
end
class CreateServicesBrands < ActiveRecord::Migration[6.1]
def change
create_table :services_brands do |t|
t.string :warehouse
t.references :brand, null: false, foreign_key: {to_table: :services_brand_details}
t.timestamps
end
end
end
Now I was able to create and save data in from ServicesBrandDetails model. but the Problem is when i create record from ServiceBrand It created record perfectly but i was not able to store data in DB.
record = ServicesBrandDetail.create(:brand => "a", :mail_list => 'abc#mail.com', :cc_list => 'def#mail.com')
record.save
Record successfully stored in DB.
child = record.services_brands.new(:warehouse => "in") <-- record was created successfully.
child.save
it give me error
C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/activerecord-6.1.5/lib/active_record/inheritance.rb:237:in `compute_type': uninitialized constant ServicesBrand::ServicesBrandDetails (NameError)
Please follow proper Naming convention
This article might help - https://www.bigbinary.com/learn-rubyonrails-book/summarizing-rails-naming-conventions
In ServiceBrand Model
class ServiceBrand < ApplicationRecord
belongs_to :brand, class_name: 'ServiceBrandDetail'
end
belongs_to should be foreign key name i.e brand in your case
You can delete existing models and tables from your codebase and try below one. (I've tested)
class ServiceBrandDetail < ApplicationRecord
has_many :service_brands, foreign_key: :brand_id, dependent: :delete_all
end
class ServiceBrand < ApplicationRecord
belongs_to :brand, class_name: 'ServiceBrandDetail'
end
Migration for both files
class CreateServiceBrandDetails < ActiveRecord::Migration[6.1]
def change
create_table :service_brand_details do |t|
t.string :brand
t.string :mail_list
t.string :cc_list
t.timestamps
end
end
end
class CreateServiceBrands < ActiveRecord::Migration[6.1]
def change
create_table :service_brands do |t|
t.string :warehouse
t.references :brand, null: false, foreign_key: {to_table: :service_brand_details}
t.timestamps
end
end
end
Then try to create model objects which you tried in your question. It will work 👍🏽
In your model ServicesBrand you have to use singular association name for belongs_to
Change this belongs_to :services_brand_details to this belongs_to :services_brand_detail
class ServicesBrand < ApplicationRecord
belongs_to :services_brand_detail, foreign_key: "brand_id"
end

How to manage multiple roles using polymorphic association in rails?

I am using devise for authentication and finding a way to get out of this.
Can I explore same design user having multiple roles ?. So that he can login as Teacher or Parent both?. Basically he can switch accounts like multiple roles.
class User < ActiveRecord
belongs_to :loginable, polymorphic: true
end
class Parent < ActiveRecord
has_one :user, as: :loginable
end
class Teacher < ActiveRecord
has_one :user, as: :loginable
end
for eg: loginable_type: "Parent", loginable_id: 123
I want to find a way to change above fields, if user is logging in as 'Teacher' and its ID.
You can add a polymorphic has_many relationship:
class CreateUserRoles < ActiveRecord::Migration
def change
create_table :user_roles do |t|
t.integer :role_id
t.integer :user_id
t.string :role_type # stores the class of role
t.timestamps
end
add_index :user_roles, [:role_id, :role_type]
end
end
class AddActiveRoleToUser < ActiveRecord::Migration
def change
change_table :user_roles do |t|
t.integer :active_role_id
t.timestamps
end
end
end
class User < ActiveRecord
has_many :roles, polymorphic: true
has_one :active_role, polymorphic: true
def has_role? role_name
self.roles.where(role_type: role_name).any?
end
end

has_one relationship is resulting in ActiveModel::MissingAttributeError , what am I missing here?

I feel like I am overlooking something obvious here. I can create a story model, and a category model, but I can't relate a story to a category.
Here is how I reproduce the error:
s = Story.new(title: "test", picture_url: "www.google.com")
c = Category.last
s.category = c
error: ActiveModel::MissingAttributeError: can't write unknown attribute `story_id'
Story model
class Story < ActiveRecord::Base
has_many :chapters, dependent: :destroy
has_many :users, through: :story_roles
has_one :category
end
Story migration file
class CreateStories < ActiveRecord::Migration
def change
create_table :stories do |t|
t.string :title
t.string :picture_url
t.integer :category_id
t.timestamps
end
end
end
Category model
class Category < ActiveRecord::Base
belongs_to :story
validates_presence_of :body
end
Category migration
class CreateCategories < ActiveRecord::Migration
def change
create_table :categories do |t|
t.string :body
t.timestamps
end
end
end
In your story model, change has_one :category to belongs_to :category. A rule of thumb is if you have a foreign key for a model, you declare the association as belongs_to. In this example, you have category_id in the story model so you use belongs_to :category in the story model. This makes perfect sense since a story should really belong to a category and a category has_many stories.
You miss t.references :story in your migration. The belongs_to method on category requires story_id.
class CreateCategories < ActiveRecord::Migration
def change
create_table :categories do |t|
t.references :story
t.string :body
t.timestamps
end
end
end
You are missing a foreign_key story_id in your Category Model. Add that column in your categories table and migrate it.That would resolve your issue.
Note: Before migrating the changes,roll back the previous migration.
OR
The best way is what #bekicot suggested. Just add t.references :story. This includes story_id,so that it will be added to your categories table by default.

Rails: How to name a attribute of a model in a specific way?

i am searching for a solution of my little problem - maybe you wanna help ^^
I have in Ruby on Rails modeled to classes "Person" and "Contact". A Person can have many contacts and a Contact can have one specific person and describes this relation with a value
class Person < ActiveRecord::Base
has_many :contacts
end
class Contact < ActiveRecord::Base
belongs_to :person
has_one :person #how to rename this?
end
In the table of the Person is nothing special, or related column to contact, but the contact table-script looks like this
class CreateContacts < ActiveRecord::Migration
def self.up
create_table :contacts do |t|
t.references :person
t.references :person #how to rename this eather?
t.integer :value
end
end
def self.down
drop_table :contacts
end
end
as i written in the source code - i dont know how to rename the second relation to person - if you can give me a hint i would be very appreciated =)
greetings
Klaf
class Person < ActiveRecord::Base
has_many :contacts
end
class Contact < ActiveRecord::Base
belongs_to :person
belongs_to :contact, :class_name => "Person"
end
#in migration
class CreateContacts < ActiveRecord::Migration
def self.up
create_table :contacts do |t|
t.references :person
t.integer :contact_id
t.integer :value
end
end
def self.down
drop_table :contacts
end
end
What about this:
class CreateContacts < ActiveRecord::Migration
def self.up
create_table :contacts do |t|
t.references :person
t.string :person_description
t.integer :value
end
end
def self.down
drop_table :contacts
end
end
remove has_one :person from Contact.
To get the description:
some_contact.person_description
I'd rename the :belongs_to to 'owner' and leave the :has_one as 'person'.
You don't need the additional has_one x relationship in your Contact model because there is already an implicit 1-1 relationship present because of the belongs_to :person association.
Note that your contacts table should have a person_id integer field to act as the foreign key.

Problem with has_many :through Association in Ruby on Rails

I've got a problem with a has_many :through association, i cant call the u1.UsersProfileAttributes.find_by_ProfileAttribute_name("icq") method, rails means that this method doesn't exist. The method u1.UsersProfileAttributes.find_by_ProfileAttribute_id(3) works correctly. u1 is a user object. I don't know whats the problem, because my associations seems to be okay. Have a look:
class ProfileAttribute < ActiveRecord::Base
has_many :UsersProfileAttributes
has_many :users, :through => :UsersProfileAttributes
end
class User < ActiveRecord::Base
has_many :UsersProfileAttributes
has_many :ProfileAttributes, :through => :UsersProfileAttributes
end
class UsersProfileAttribute < ActiveRecord::Base
belongs_to :user
belongs_to :ProfileAttribute
end
My Migration file:
class CreateProfileAttributes < ActiveRecord::Migration
def self.up
create_table :profile_attributes do |t|
t.string :name
t.integer :profile_group_id
t.timestamps
end
create_table :users_profile_attributes do |t|
t.integer :user_id
t.integer :ProfileAttribute_id
t.string :value
end
end
def self.down
drop_table :profile_attributes
drop_table :users_profile_attributes
end
end
You need to query ProfileAttributes, not UsersProfileAttributes. This should work for you: u1.ProfileAttributes.find_by_name('icq')
u1.UsersProfileAttributes.find_by_ProfileAttribute_id(3) works because ProfileAttribute_id is an attribute of UsersProfileAttribute ... so ActiveRecord builds you a dynamic finder.
u1.UsersProfileAttributes.find_by_ProfileAttribute_name("icq") does not work because ProfileAttribute_name is not an attribute of UsersProfileAttribute.

Resources