Associations and (several) foreign keys in rails (3.2): how to describe them in a model and record migrations

I have 3 models: question, option, rule

Question has_many options; Option requires foreign key for question_id

The rules table consists of 3 foreign_keys:

  • 2 columns / links for question_ids → foreign keys with the names "guess_question_id" and "followent_question_id"
  • 1 column / link to option_id -> foreign key named option_id or condition_id

Associations for the rule: Question has_many rules; as well as the has_one option rule

I want to understand how to write migrations for this, and how it is associated with the 'has_many' / 'belongs_to' operations that I write in my model, and the ': foreign_key' parameter, which I can include in my model.

I had this for my parameter migration, but I'm not sure how the add_index operator works in terms of foreign keys and how I can use it for my Rule migration: (my question and option models have corresponding has_many and applies to operators - and it works fine)

class CreateOptions < ActiveRecord::Migration def change create_table :options do |t| t.integer :question_id t.string :name t.integer :order t.timestamps end add_index :options, :question_id end end 

Thanks for the help!

+1
ruby-on-rails migration associations
Jul 12 '12 at 18:17
source share
3 answers

add_index adds a pointer to the specified column, no more.

Rails does not provide native migration support for managing foreign keys. Such functionality is included in gems such as a foreigner . Read the documentation in which the stone is to find out how it is used.

As for associations, just add the columns that you mentioned in your Question to each table (the migration you provided looks great, maybe it is missing :rule_id ?)

Then indicate the associations in your models. To get started

 class Question < ActiveRecord::Base has_many :options has_many :assumption_rules, class_name: "Rule" has_many :consequent_rules, class_name: "Rule" end class Rule < ActiveRecord::Base belongs_to :option belongs_to :assumption_question, class_name: "Question", foreign_key: :assumption_question_id, inverse_of: :assumption_rules belongs_to :consequent_question, class_name: "Question", foreign_key: :consequent_question_id, inverse_of: :consequent_rules end class Option < ActiveRecord::Base belongs_to :question has_one :rule end 

Note This is a simple (untested) start; options may not be available.

I highly recommend you read

Edit: To answer the question in your comment

 class Option < ActiveRecord::Base belongs_to :question # ... 

belongs_to tells rails that the question_id column in the options table holds the id value for the entry in your questions table. Rails guesses the column name is question_id based on the character :question . You can tell rails to look at another column in the options table by specifying a parameter, for example foreign_key: :question_reference_identifier , if that was the name of the column. (Note that your Rule class in my code above uses the foreign_key parameter this way).

Your migrations are nothing more than instructions that Rails will read and execute commands in your database based on. Associations of your models ( has_many , belongs_to , etc.) inform Rails about how you want Active Record to work with your data, providing you with a simple and clear way to interact with your data. Models and migrations never interact with each other; they both interact independently with your database.

+1
Jul 12 2018-12-12T00:
source share

Note: I found this method to solve the problem. Incredibility from China.

If you have RailsAdmin with you, you may notice that you can see all the rules of one question if one field of both fields of the question (predption_question_id, followent_question_id) is equal to the id of the question.

I did a detailed test on this issue and found out that Rails always generates a question_id = [current_id] condition that makes to_sql outputs

 SELECT `rules`.* FROM `rules` WHERE `rules`.`question_id` = 170 

And the reason the next model is

 class Question < ActiveRecord::Base has_many :options # Notice ↓ has_many :rules, ->(question) { where("assumption_question_id = ? OR consequent_question_id = ?", question.id, question.id) }, class_name: 'Rule' # Notice ↑ end 

does Question.take.rules.to_sql this way

 SELECT `rules`.* FROM `rules` WHERE `rules`.`question_id` = 170 AND (assumption_question_id = 170 OR consequent_question_id = 170) 

Don't we get to the annoyance of question_id yet, so no matter how we describe or properly define, our condition follows that "AND".

Then we need to ride. How?

Click here and you will learn how to find sector 8.1 , and you can see

 Article.where(id: 10, trashed: false).unscope(where: :id) # SELECT "articles".* FROM "articles" WHERE trashed = 0 

Then let's do it:

 class Question < ActiveRecord::Base has_many :options # Notice ↓ has_many :rules, ->(question) { unscope(where: :question_id).where("assumption_question_id = ? OR consequent_question_id = ?", question.id, question.id) }, class_name: 'Rule' # Notice ↑ end class Rule < ActiveRecord::Base belongs_to :option belongs_to :assumption_question, class_name: "Question", foreign_key: :assumption_question_id, inverse_of: :assumption_rules belongs_to :consequent_question, class_name: "Question", foreign_key: :consequent_question_id, inverse_of: :consequent_rules end class Option < ActiveRecord::Base belongs_to :question has_one :rule end 

Done.

Finally

This is my first answer here on stackoverflow, and this method is never found anywhere else.

Thanks for reading.

+1
Nov 04 '16 at 15:58
source share

You can set the foreign key in your model as follows:

 class Leaf < ActiveRecord::Base belongs_to :tree, :foreign_key => "leaf_code" end 

You do not need to specify this in the migration, the rails pull the foreign key out of the model class definition.

0
Jan 10 '13 at 21:32
source share



All Articles