How do I write this has_many_to_many dependency? - ruby-on-rails

I am trying to create a has many to many relationship between a Goal model. A goal can have dependent goals and a goal can have others goals that rely on it.
So far I have come up with the below, but it does not seem to be working.
class Goal < ActiveRecord::Base
belongs_to :goal_status
belongs_to :goal_type
has_many :users, through: :user_goals
has_many :user_goals
has_many :dependers, class_name: 'GoalDependency', foreign_key: :dependee_id
has_many :dependees, class_name: 'GoalDependency', foreign_key: :depender_id
has_many :dependencies, through: :dependees
has_many :depending, through: :dependers
validates_presence_of :goal_status_id, :goal_type_id
end
class GoalDependency < ActiveRecord::Base
belongs_to :dependee, class_name: 'Goal', foreign_key: 'dependee_id'
belongs_to :depender, class_name: 'Goal', foreign_key: 'depender_id'
end
Schema
create_table "goal_dependencies", force: :cascade do |t|
t.integer "dependee_id"
t.integer "depender_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "goals", force: :cascade do |t|
t.integer "goal_status_id"
t.integer "goal_type_id"
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
I am getting the error
Could not find the source association(s) "dependency" or :dependencies in model GoalDependency. Try 'has_many :dependencies, :through => :dependees, :source => <name>'. Is it one of dependee or depender?
I have tried putting in a couple of different values as the source, but nothing is working. I am not really familiar that much with using source.
I would guess this is possible in rails. Any ideas?

After taking #Pavan's advice I changed the language around and managed to get it working that way. See the code below.
class Goal < ActiveRecord::Base
belongs_to :goal_status
belongs_to :goal_type
has_many :users, through: :user_goals
has_many :user_goals
has_many :parent_goals, class_name: 'GoalDependency', foreign_key: :parent_id
has_many :child_goals, class_name: 'GoalDependency', foreign_key: :child_id
has_many :children, through: :child_goals
has_many :parents, through: :parent_goals
validates_presence_of :goal_status_id, :goal_type_id
end
class GoalDependency < ActiveRecord::Base
belongs_to :parent, class_name: 'Goal', foreign_key: 'parent_id'
belongs_to :child, class_name: 'Goal', foreign_key: 'child_id'
end
Schema
create_table "goals", force: :cascade do |t|
t.integer "goal_status_id"
t.integer "goal_type_id"
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "goal_dependencies", force: :cascade do |t|
t.integer "parent_id"
t.integer "child_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

Related

Rails : double association with same Model

I created a double "Synonym" association with the same Word model as following:
class Synonym < ApplicationRecord
belongs_to :word_origin, :class_name => "Word"
belongs_to :word_synonym, :class_name => "Word"
end
Here is my Word model:
class Word < ApplicationRecord
has_many :word_synonyms, :class_name => 'Word', :foreign_key => 'word_synonym_id', dependent: :destroy
has_many :word_origins, :class_name => 'Word', :foreign_key => 'word_origin_id', dependent: :destroy
end
However, when I try to delete a word, I get the following error:
ActiveRecord::StatementInvalid (PG::UndefinedColumn: ERROR: column
words.word_synonym_id does not exist)
Any idea what's wrong with my double association? Thanks.
EDIT: here is the schema of Word and Synonym
create_table "words", force: :cascade do |t|
t.string "content"
t.string "slug"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["content"], name: "index_words_on_content", opclass: :gin_trgm_ops, using: :gin
end
create_table "synonyms", force: :cascade do |t|
t.bigint "word_origin_id"
t.bigint "word_synonym_id"
t.index ["word_origin_id"], name: "index_synonyms_on_word_origin_id"
t.index ["word_synonym_id"], name: "index_synonyms_on_word_synonym_id"
end
Word is referencing itself without the needed columns. You have to change the line to be
has_many :word_synonyms, class_name: 'Synonym',
foreign_key: 'word_synonym_id', dependent: :destroy
has_many :word_origins, class_name: 'Synonym',
foreign_key: 'word_origin_id', dependent: :destroy

Rails - Polymorphic has_many :through with model not building on create

My has_many :through model (Posting) is not building an object on creation of the primary associated object (Post). How can I build the relationship on creation?
Models:
class Post
has_many :postings, dependent: :destroy
has_many :products, through: :postings, source: :postable, source_type: "Product"
has_many :Items, through: :postings, source: :postable, source_type: "Item"
end
class Posting
belongs_to :postable, polymorphic: true
belongs_to :post
end
class Product
has_many :postings, as: :postable
has_many :posts, through: :postings
end
class Item
has_many :postings, as: :postable
has_many :posts, through: :postings
end
Schema:
create_table "postings", force: :cascade do |t|
t.bigint "postable_id"
t.string "postable_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "post_id"
t.index ["post_id"], name: "index_postings_on_post_id"
end
create_table "posts", force: :cascade do |t|
t.string "title"
t.string "slug"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Console:
Post.create(title: "Foo", product_id:3)
Traceback (most recent call last):
1: from (irb):12
ActiveModel::UnknownAttributeError (unknown attribute 'product_id' for Post.)
Appreciate any tips!

Ruby on Rails associations for has_many, through, source returns NoMethodError

I have three models user.rb, vote.rb, and event.rb
User
has_many :votes, foreign_key: 'voter_id', dependent: :destroy
has_many :voting, through: :votes, source: :voted
Vote
belongs_to :voter, class_name: "User"
belongs_to :voted, class_name: "Event"
Event
has_many :votes, foreign_key: 'voted_id', dependent: :destroy
has_many :voters, through: :votes, source: :voter
For some reason, if I call User.first.voting I get: NoMethodError: undefined method 'voted' for #<User:0x00007fbc56d069d8>
Anybody know why? I have googled a few other questions regarding this topic and I don't see where I am going wrong.
If you're on rails 5, I made a working code:
User
has_many :votes, foreign_key: 'voter_id', dependent: :destroy
has_many :voting, through: :votes, source: :voted
Event
has_many :votes, foreign_key: 'voted_id', dependent: :destroy
has_many :voters, through: :votes, source: :voter
Vote
belongs_to :voter, class_name: "User", optional: true
belongs_to :voted, class_name: "Event", optional: true
Schema
create_table "events", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "votes", force: :cascade do |t|
t.integer "voter_id"
t.integer "voted_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
To test (rails console)
> User.create
> Event.create
> Vote.create(:voter_id => 1, :voted_id => 1)
> User.first.voting
=> #<ActiveRecord::Associations::CollectionProxy
> User.first.voting.first # to get event instance
=> #<Event ...
Hope this helps!

Rails self-referential has_many association

Using Ruby on Rails, I think I need to create a self-referential has_many association to model words in Chinese.
Background:
Each word is a composite of multiple component words.
For example, if I have three words, 'ni', 'hao', and 'nihao', I want to be able to do:
nihao.components = ['ni', 'hao']
and
'ni'.composites = ['nihao']
'hao'.composites =['nihao']
I don't believe this should be a hierarchical association (I've seen several gems... ) because a word doesn't have 1 or 2 "parents", it has 0, 1, or hundreds of "composites". Likewise a word has 0, 1, or several "components".
I've tried:
class Word < ActiveRecord::Base
has_many :relationships
has_many :components, through: :relationships, foreign_key: :component_id
has_many :composites, through: :relationships, foreign_key: :composite_id
end
class Relationship < ActiveRecord::Base
belongs_to :component, class_name: "Word"
belongs_to :composite, class_name: "Word"
end
This isn't quite correct as I am unable to add components:
nihao.components << ni
(0.2ms) BEGIN
(0.2ms) ROLLBACK
ActiveModel::UnknownAttributeError: unknown attribute 'word_id' for Relationship.
from (irb):5
Database schema:
create_table "relationships", force: :cascade do |t|
t.integer "component_id"
t.integer "composite_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "words", force: :cascade do |t|
t.string "characters"
t.string "pinyin"
t.string "opinyin"
t.string "tpinyin"
t.string "english"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Try this, you were not associating your models properly for this kind of use case.
class Word < ActiveRecord::Base
has_many :component_relationships, class_name: 'Relationship', foreign_key: :composite_id
has_many :composite_relationships, class_name: 'Relationship', foreign_key: :component_id
has_many :components, through: :component_relationships
has_many :composites, through: :composite_relationships
end
class Relationship < ActiveRecord::Base
belongs_to :component, class_name: "Word", foreign_key: :component_id
belongs_to :composite, class_name: "Word", foreign_key: :composite_id
end
I have not tried this, but this should work.

Has many associations error when not using default column name

I cannot make good associations when the foreign key has not the default name.
I would like to access to all subjects which belongs_to one participant (foreign key = questioner_id).
It raise me an error
p = Participant.first
p.subjects
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: subject_participants.participant_id: SELECT "participants".* FROM "participants" INNER JOIN "subject_participants" ON "participants"."id" = "subject_participants"."subject_id" WHERE "subject_participants"."participant_id" = ?
Why does it looks for subject_participants.participant_id ? It's just a has_many association, I don't think that subject_participants table should be called in this case...
interested_id and questioner_id are from the same model but not the same role. One has to go through subject_participants table and the other has to go directly in subjects table
My models :
participant.rb
class Participant < ActiveRecord::Base
has_many :subjects, foreign_key: "questioner_id", class_name: "Participant" #questioner
has_many :subjects, through: :subject_participants, foreign_key: "interested", class_name: "Participant" #interested
has_many :subject_participants
has_many :conference_participants
has_many :conferences, through: :conference_participants
end
subject.rb
class Subject < ActiveRecord::Base
validates_presence_of :title, :questioner, :conference, :description
has_many :subject_participants
has_many :interested, through: :subject_participants, :class_name => "Participant" #interested
belongs_to :questioner, :class_name => "Participant"
belongs_to :conference
end
subject_participant.rb
class SubjectParticipant < ActiveRecord::Base
validates_presence_of :interested_id, :subject_id
belongs_to :interested, :class_name => "Participant"
belongs_to :subject
end
schema.rb
create_table "participants", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
end
add_index "participants", ["email"], name: "index_participants_on_email", unique: true
add_index "participants", ["reset_password_token"], name: "index_participants_on_reset_password_token", unique: true
create_table "subject_participants", force: :cascade do |t|
t.integer "interested_id"
t.integer "subject_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "subjects", force: :cascade do |t|
t.string "title", null: false
t.text "description"
t.integer "questioner_id", null: false
t.integer "conference_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Change your participant.rb to
class Participant < ActiveRecord::Base
.....
has_many :subject_participants,class_name: "SubjectParticipant", foreign_key: "interested_id"
end
You make me find the solution, thanks for help :
participant.rb
class Participant < ActiveRecord::Base
has_many :subject_participants, class_name: "SubjectParticipant", foreign_key: "interested_id"
has_many :subjects_interested_in, through: :subject_participants, :source => "subject"
has_many :subjects, foreign_key: "questioner_id"
has_many :conference_participants
has_many :conferences, through: :conference_participants
end
subject.rb
class Subject < ActiveRecord::Base
validates_presence_of :title, :questioner, :conference, :description
has_many :subject_participants
has_many :interested, through: :subject_participants #interested
belongs_to :questioner, class_name: "Participant"
belongs_to :conference
end

Resources