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.
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 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)
I'm trying to build a rating system into my app and currently stuck on the associations and indices. I'm quite new to this so I need all the help I can get...
User model
class User < ActiveRecord::Base
has_many :demos
has_many :ratings
has_many :reviewed, through: :ratings, source: :reviewed'Demo'
That's part of it.
Demo model
class Demo < ActiveRecord::Base
belongs_to :user
belongs_to :subject
has_many :ratings
has_many :reviewers, through: :ratings, source: :reviewer
The subject is irrelevant.
Rating model
class Rating < ActiveRecord::Base
belongs_to :reviewed
belongs_to :reviewer
validates :rating, presence: true, numericality: { :greater_than_or_equal_to => 0, :less_than_or_equal_to => 5}
end
end
And now you can tell I'm not really sure what I'm doing.
Ratings Migration Table
class CreateRatings < ActiveRecord::Migration
def change
create_table :ratings do |t|
t.float :rating, default: 2.5
t.belongs_to :reviewed, index: true
t.belongs_to :reviewer, index: true
t.timestamps null: false
end
end
end
Demos Migration Table
class CreateDemos < ActiveRecord::Migration
def change
create_table :demos do |t|
t.references :user, index: true
t.references :subject, index: true
t.string :name
t.text :content
t.string :materials
t.timestamps null: false
end
add_index :demos, [:user_id, :subject_id, :created_at]
end
end
I haven't built a controller for ratings yet since I'm just testing the relationships using the sandbox console.
I've successfully created a Rating, but #user.reviewed and #user.ratings returns a blank array in the Active Record even though #rating has all the Demo and User ids.
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.
I'm trying design a model which has relation to itself
Model:
class Department < ActiveRecord::Base
belongs_to :organization
has_many :positions
has_many :sub_departments, class: 'Department', foreign_key: 'parent_id'
end
Migration:
class CreateDepartments < ActiveRecord::Migration
def change
create_table :departments do |t|
t.string :name
t.references :parent, index: true
t.references :organization, index: true
t.timestamps
end
end
end
When I call Department.first.sub_departments I get an error: NoMethodError: undefined method 'relation_delegate_class' for "Department":String. What am I doing wrong?
Thanks!
I think you should use class_name: instead of class:.