I am trying to make a many-to-many association in an RoR program, but I can't get rid of the error I mentioned in the title, the command I am using in the Rails console is:
User.find(1).attended_events = [Event.find(1)]
I need to solve this problem and can't find anywhere, I appreciate any help.
My code:
Models
class User < ApplicationRecord
has_many :created_events,class_name:"Event"
has_many :hosts
has_many :attended_events, through: :hosts
end
class Host < ApplicationRecord
belongs_to :attended_event, class_name:"Event"
belongs_to :attendee, class_name:"User"
end
class Event < ApplicationRecord
belongs_to :creator, foreign_key: :user_id, class_name:'User'
has_many :hosts
has_many :attendees, through: :hosts
end
Migration Files
class CreateUsers < ActiveRecord::Migration[6.0]
def change
create_table :users do |t|
t.string :name
t.string :email
t.timestamps
end
end
end
class CreateHosts < ActiveRecord::Migration[6.0]
def change
create_table :hosts do |t|
t.references :attendee, null: false, foreign_key: true
t.references :attended_event, null: false, foreign_key: true
t.integer :user_id
t.integer :event_id
t.timestamps
end
end
end
class CreateEvents < ActiveRecord::Migration[6.0]
def change
create_table :events do |t|
t.string :date
t.text :description
t.references :user, null: false, foreign_key: true
t.timestamps
end
end
end
Read about the foreign_key option for has_many.
class Event < ApplicationRecord
belongs_to :creator, foreign_key: :user_id, class_name:'User'
has_many :hosts
has_many :attendees, through: :hosts
end
These model associations are wrong, the error is in the second line.
class Event < ApplicationRecord
belongs_to :creator, foreign_key: :user_id, class_name:'User'
has_many :hosts
has_many :attendees, through: :hosts
end
With these model associations, you need to specify the foreign_key for the has_many :hosts statement.
class Host < ApplicationRecord
belongs_to :attended_event, class_name:"Event"
belongs_to :attendee, class_name:"User"
end
Here are my suggestions:
User
class User < ApplicationRecord
has_many :created_events, foreign_key: 'user_id'
has_many :hosts, foreign_key: 'attendee_id'
has_many :attended_events, through: :hosts
end
Host
class Host < ApplicationRecord
belongs_to :attended_event, class_name: 'Event'
belongs_to :attendee, class_name: 'User'
end
Event
class Event < ApplicationRecord
belongs_to :creator, class_name: 'User'
has_many :hosts, foreign_key: 'attended_event_id'
has_many :attendees, through: :hosts
end
Your hosts migration
Better avoid passing the foreign_key here, it will look for an attendees table and a attended_events table in the database.
class CreateHosts < ActiveRecord::Migration[6.0]
def change
create_table :hosts do |t|
# t.references :attendee, null: false, foreign_key: true
t.references :attendee, null: false
# t.references :attended_event, null: false, foreign_key: true
t.references :attended_event, null: false
t.timestamps
end
end
end
Define source on through association
class User < ApplicationRecord
has_many :created_events, class_name:"Event"
has_many :hosts
has_many :attended_events, through: :hosts, source: :event
end
class Host < ApplicationRecord
belongs_to :event
belongs_to :user
end
class Event < ApplicationRecord
belongs_to :creator, foreign_key: :user_id, class_name:'User'
has_many :hosts
has_many :attendees, through: :hosts, source: :user
end
class CreateHosts < ActiveRecord::Migration[6.0]
def change
create_table :hosts do |t|
t.references :user, null: false, foreign_key: true
t.references :event, null: false, foreign_key: true
t.timestamps
end
end
end
Then you can do
User.find(1).attended_events << Event.find(1)
Related
I am new learner. I just started learning more about Backend with Ruby on Rails.
I have the following tables - User and User_Transaction.
So basically I want to have a transaction which holds information about the sender and the receiver. This personally sounds to me more like a has_and_belongs_to_many relation. However, I am really confused in how to approach this and how should I include the 2 foreign keys.
I am curious to learn more about this and I will be really happy if someone helps me :).
Migrations
User
class CreateUsers < ActiveRecord::Migration[6.0]
def change
create_table :users do |t|
t.integer :username
t.integer :password
t.timestamps
end
end
end
Transaction
class CreateTransactions < ActiveRecord::Migration[6.0]
def change
create_table :transactions do |t|
t.string :sender
t.string:receiver
t.decimal :amount
t.timestamps
end
end
end
Models
Transaction
class ::Transaction < ApplicationRecord
#We have two users per transaction 'Sender' and 'Receiver'
has_and_belongs_to_many :users
# belongs_to :sender, :class_name => 'User'
# belongs_to :receiver, :class_name => 'User'
end
User
class User < ApplicationRecord
# has_many :accounts
# has_many :transactions
has_and_belongs_to_many :transactions
end
how about this:
migrations
class CreateUsers < ActiveRecord::Migration[6.0]
def change
create_table :users do |t|
t.string :username
t.string :password
t.timestamps
end
end
end
class CreateTransactions < ActiveRecord::Migration[6.0]
def change
create_table :transactions do |t|
t.references :sender, index: true, null: false, foreign_key: {to_table: :users}
t.references :receiver, index: true, null: false, foreign_key: {to_table: :users}
t.decimal :amount
t.timestamps
end
end
end
models
class User < ApplicationRecord
has_many :send_transactions, class_name: "Transaction", foreign_key: :sender, inverse_of: :sender
has_many :receive_transactions, class_name: "Transaction", foreign_key: :receiver, inverse_of: :receiver
end
class Transaction < ApplicationRecord
belongs_to :sender, class_name: "User", inverse_of: :send_transactions
belongs_to :receiver, class_name: "User", inverse_of: :receive_transactions
end
I am trying to figure out what's the best way to handle namespaced models. Here's the models that i have in my project:
class Member < ApplicationRecord
has_one :ledger, inverse_of: :member, class_name: "Member::Ledger", dependent: :destroy
has_many :ledger_entries, through: :ledger
end
class Member::Ledger < ApplicationRecord
belongs_to :member, inverse_of: :ledger
has_many :ledger_entries, foreign_key: "member_ledger_id", dependent: :destroy
end
class Member::LedgerEntry < ApplicationRecord
belongs_to :ledger, foreign_key: "member_ledger_id"
end
And here's how my migrations files look like:
create_table :members do |t|
t.timestamps
end
create_table :member_ledgers do |t|
t.references :member, foreign_key: true, null: false, index: { unique: true }
t.timestamps
end
create_table :member_ledger_entries do |t|
t.references :member_ledger, foreign_key: true, null: false
t.timestamps
end
So I have few questions here:
Are migration files correct? I mean should i have member_ledger_id in the member_ledger_entries table or just ledger_id?
Are associations defined in a correct way? Even though this works but i am not sure this is how we are supposed to proceed.
I am using ruby-2.5.1 and rails-5.2.0.
Any help would be appreciated. Thanks in advance !!
Perhaps your associations could look more like:
class Member < ApplicationRecord
has_one :member_ledger, inverse_of: :member, dependent: :destroy
has_many :member_ledger_entries, through: :member_ledger
end
class Member::Ledger < ApplicationRecord
belongs_to :member, inverse_of: :member_ledger
has_many :member_ledger_entries, dependent: :destroy
end
class Member::LedgerEntry < ApplicationRecord
belongs_to :member_ledger
end
I have this two models:
class Answer < ActiveRecord::Base
belongs_to :user
belongs_to :question
has_many :edits, dependent: :destroy
end
class Question < ActiveRecord::Base
belongs_to :user
has_many :answers, dependent: :destroy
end
But when I write in rails console following:
q=Question.new
q.save
a=Answer.new
a.question = q
a.save
q.answers.size
It gives me zero.
irb(main):026:0> q.answers.size
=> 0
But when I write this:
Answer.where(:question_id => q.id).size
it gives me 1
SO WHAT DO I DO?
In case you need it - answers and question migrations:
class CreateAnswers < ActiveRecord::Migration
def change
#execute "DROP TABLE #{:answers} CASCADE"
create_table :answers do |t|
t.text :body
t.references :user, index: true, foreign_key: true
t.references :question, index: true, foreign_key: true
t.timestamps null: false
end
end
end
class CreateQuestions < ActiveRecord::Migration
def change
#execute "DROP TABLE #{:questions} CASCADE"
create_table :questions do |t|
t.string :title
t.text :body
t.references :user, index: true, foreign_key: true
t.timestamps null: false
end
end
end
You need to use inverse_of option in your relationship.
class Answer < ActiveRecord::Base
belongs_to :user
belongs_to :question, inverse_of: answers
has_many :edits, dependent: :destroy
end
class Question < ActiveRecord::Base
belongs_to :user
has_many :answers, inverse_of: question, dependent: :destroy
end
So when you do:
a.question = q
Rails will do this for you(in memory):
q.answers << a
And you don't need to reload the q again.
Team, looking for some help for a very specific (newbie) situation on a Rails 4 association.
We have 3 models:
class Brand < ActiveRecord::Base
has_many :lines, dependent: :destroy
has_many :products, through: :lines, dependent: :destroy
end
class Line < ActiveRecord::Base
belongs_to :brand
has_and_belongs_to_many :products
end
class Product < ActiveRecord::Base
has_and_belongs_to_many :lines
has_many :brands, through: :lines
end
This configuration works well when trying to check for Products under specific Brand (or Line) and viceversa: different Brands (or Lines) available for a specific Product. However, when it comes to delete/destroy there is an issue. We are getting this Rspec error:
ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection:
Cannot modify association 'Brand#products' because the source reflection
class 'Product' is associated to 'Line' via :has_and_belongs_to_many.
We have made research on this exception, checked for Rails API, with no luck, examples found are showing a different model configuration. What's missing on this approach?
Appreciate your help guys!
In my opinion, it should be something like this:
class Brand < ActiveRecord::Base
has_many :lines, dependent: :destroy
has_many :products, through: :lines, dependent: :destroy
end
class Line < ActiveRecord::Base
belongs_to :brand
has_and_belongs_to_many :products
end
class Product < ActiveRecord::Base
belongs_to :brand, through: :line
has_and_belongs_to_many :lines
end
And in migrations:
create_table :brands , force: true do |t|
t.string :name
...
t.timestamps null: false
end
create_table :lines , force: true do |t|
t.string :name
t.belongs_to :brand
...
t.timestamps null: false
end
create_table :products , force: true do |t|
t.string :name
...
t.timestamps null: false
end
create_table :line_products, force: true, id: false do |t|
t.belongs_to :line, index: true
t.belongs_to :product, index: true
end
I hope it will help.
This is my Migration code:
1.User
create_table :users do |t|
t.string :name
t.string :password
t.string :department
t.timestamps
end
2.Ploy
create_table :ploys do |t|
t.string :name
t.string :state
t.string :description
t.string :location
t.float :spend
t.references :creator, index: true, class_name: "User"
t.timestamps
end
3.participants
def change
create_table :participants do |t|
t.belongs_to :ploy
t.belongs_to :user
t.timestamps
end
This is my Model code:
class User < ActiveRecord::Base
has_one :create_ploys, class_name: "Ploy"
has_many :participants
has_many :ploys, through: :participants, source: :join_ploys
end
class Ploy < ActiveRecord::Base
belongs_to :creator, class_name: "User"
has_many :participants
has_many :users, through: :participants, source: "joiners"
end
class Participant < ActiveRecord::Base
belongs_to :user
belongs_to :ploy
end
When i call user.join_ploys, but give me a error: NoMethodError: undefined method `join_ploys'
So i think maybe something is wrong about :source, But i don't know how to do.
so where are you defining a model or association for joiners and join_ploys? You can't just create a :source without defining what it is. Check out this SO: Need help to understand :source option of has_one/has_many through of Rails