I'm trying to make a has_many relation work for object to be created.
It is a simple case and despite many efforts and researches through the web, I cannot find why my code is not working.
I have the following classes (note: some variables use French names):
class Comptes::Category < ActiveRecord::Base
has_many :categorizations, dependent: :destroy
accepts_nested_attributes_for :categorizations
has_many :transactions, through: :categorizations
validates :nom, presence: true, uniqueness: true
end
class Comptes::Transaction < ActiveRecord::Base
has_many :categorizations, dependent: :destroy
accepts_nested_attributes_for :categorizations
has_many :categories, through: :categorizations
... # some validations
end
class Comptes::Categorization < ActiveRecord::Base
belongs_to :transaction
belongs_to :category
validates :transaction, presence: true
validates :category, presence: true
end
Category and Transaction are the basic models and Categorization is dedicated to the association (this is a basic account - transaction system).
What I can do is create a transaction and a category then fill transaction.categories with the category (transaction has thus an id).
What I cannot do is:
transaction = Comptes::Transaction.new ...
category = Comptes::Category.first
transaction.categories << category
# OR
transaction.categorizations.build category: category
# OR
# use categorizations_attributes in and accepts_nested_attributes_for.
Thank you very much for any help
Edit: this is done in rails 4.0.0
And I found that the issue was coming from the validation in Comptes::Categorization.
This prevents creation of new categorizations if the transaction or category does not exist yet.
Update (18/08/2014): the issue is coming from the validation in Categorizations, which prevent from creating the association without existing transaction and category. This may be an issue in rails 4.0.0. To see...
Transaction class is not under the module Comptes. Therefore, when you do has_many :categorizations or has_many :categories in it, the corresponding models are inferred as Categorization and Category instead of Comptes::Categorization and Comptes::Category.
To resolve this, you need to specify the class_name option of the association because the name of the model can't be inferred from the association name.
Update the class Transaction as below:
class Transaction < ActiveRecord::Base
has_many :categorizations, class_name: "Comptes::Categorization" , dependent: :destroy
accepts_nested_attributes_for :categorizations
has_many :categories, through: :categorizations, class_name: "Comptes::Category"
end
Related
Let's say I have three models: Organization, Skills and Assessments.
Can an Assessment belong to two different Organizations, via different relations?
For example, an assessment may have happened at organization A, but was based on a skill belonging to organization B.
Below are my models and associations:
class Organization < ActiveRecord::Base
has_many :checklists
has_many :levels, :through => :checklists
has_many :sections, :through => :levels
has_many :skills, :through => :sections
has_many :assessments_using_own_checklists, :through => :skills, :source => :assessments
end
class Skill < ActiveRecord::Base
belongs_to :section
has_one :level, through: :section
has_one :checklist, through: :level
has_one :organization, through: :checklist
has_many :assessments
end
class Assessment < ActiveRecord::Base
belongs_to :skill
has_one :section, through: :skill
has_one :level, through: :section
has_one :checklist, through: :level
has_one :checklist_owner, through: :checklist, source: :organization
belongs_to :organization
end
Using the above, I can get an assessment's organization:
Assessment.last.organization # yields organization 1
I can also get an assessment's checklist_owner:
Assessment.last.checklist_owner # yields organization 2
But when I try to use checklist_owner in a where, the association seems to forget to use the :through. For example, if I run:
Assessment.where(organization: Organization.find(2), checklist_owner: Organization.find(1))
... this translates to SQL:
SELECT "assessments".* FROM "assessments" WHERE "assessments"."organization_id" = 2 AND "assessments"."organization_id" = 1
See how the SQL has two "assessments"."organization_id" = statements? Why does it do that?
Have you tried using joins?
something like:
Assessment.joins(skill: { section: { level: :checklist } }).where(organization: Organization.find(2), checklists: { organization_id: Organization.find(1) })
I know it look bad, but it seems that your relation from assessment to checklist is very complicated. This would take care of any weird relations being made.
I have models - Test, Question, and TeacherAnswers.
test.rb
class Test < ActiveRecord::Base
has_many :questions, dependent: :destroy
accepts_nested_attributes_for :questions
end
question.rb
class Question < ActiveRecord::Base
belongs_to :test
has_many :teacher_answers, dependent: :destroy
accepts_nested_attributes_for :teacher_answers
end
teacher_answer.rb
class TeacherAnswer < ActiveRecord::Base
belongs_to :question
end
and controllers
test_controller.rb
---
standard scaffold code
---
def test_params
params.require(:test).permit(:title,
questions_attributes: [:question_text, :test_id, teacher_answers_attributes: [:teacher_answer_text, :correct, :question_id]],)
end
question_controller.rb
---
standard scaffold code
---
def question_params
params.require(:question).permit(:question_text, :test_id,
teacher_answers_attributes: [:teacher_answer_text, :correct, :question_id])
end
When creating new test with questions and answers it creates everything correctly, but when updating:
can't remove questions
when saving it doesn't update the questions and answers, but saves new ones with already old ones i.e. when updating test with 2 questions, after saving it will have 4 questions.
You should permit :id and :_destroy in the test_params like below for the update and delete to work correctly.
def test_params
params.require(:test).permit(:title, questions_attributes: [:id, :question_text, :test_id, :_destroy, teacher_answers_attributes: [:id, :teacher_answer_text, :correct, :question_id, :_destroy]])
end
Update
You should also add allow_destroy: true for test.rb and question.rb
class Test < ActiveRecord::Base
has_many :questions, dependent: :destroy
accepts_nested_attributes_for :questions, allow_destroy: true
end
class Question < ActiveRecord::Base
belongs_to :test
has_many :teacher_answers, dependent: :destroy
accepts_nested_attributes_for :teacher_answers, allow_destroy: true
end
accepts_nested_attributes_for by default does not allow deletion, use delete: true
Pass id to form, via hidden tag
I have a Store model, Product model, and a StoreProduct model to form a many-to-many relationship between stores and products.
The StoreProduct model, on top of store_id and product_id, has an attribute price:float.
I'm struggling to figure out how I can design a form to create a new product given the store. Is it better off making a form for a new StoreProduct object? What is the conventional way of doing this?
store.rb
class Store < ActiveRecord::Base
validates :name, presence: true
has_many :store_products
has_many :products, through: :store_products
end
product.rb
class Product < ActiveRecord::Base
validates :name, presence: true
validates_numericality_of :price, on: :create
has_many :reviews
has_many :users, through: :reviews
has_many :store_products
has_many :stores, through: :store_products
end
store_product.rb
class StoreProduct < ActiveRecord::Base
belongs_to :store
belongs_to :product
end
I have two basic models:
class Case < ActiveRecord::Base
has_many :contacts
end
class Contact < ActiveRecord::Base
belongs_to :case
belongs_to :contactable, :polymorphic => true, :foreign_key => :contactable_id
end
I also have quite a few models that are "sub types" of the Contact model:
class Attorney < ActiveRecord::Base
has_one :contact, as: :contactable, dependent: :destroy
accepts_nested_attributes_for :contact
end
class Client < ActiveRecord::Base
has_one :contact, as: :contactable, dependent: :destroy
accepts_nested_attributes_for :contact
end
I used polymorphic associations instead of STI because I don't want one table to store all the fields, which can get a little slow and overwhelming.
I am wondering if the has_many :contacts line from the Case model is correct. I try to use it in my console, but it doesn't really work the way I expected. Am I missing something?
I basically want an association where a Case can have many Contacts and a contact can belong to many cases. The contact can be of any type (Attorney or Client or Contact by itself). I was hoping it was as easy as case has_many :contacts
I have two models for Show and Performance (show as in a play or comedy show). They are associated like this in the models:
class Show < ActiveRecord::Base
has_many :performances, :dependent => :destroy
accepts_nested_attributes_for :performances
end
class Performance < ActiveRecord::Base
belongs_to :show
end
In the Performance model there is a datetime called :start_time.
How do I define a scope in the model which returns all Shows with at least one performance whose :start_time is in the future?
Also, how do I define a scope that returns all Shows that do not have any performances in whose :start_time is in the future?
class Show < ActiveRecord::Base
has_many :performances, :dependent => :destroy
accepts_nested_attributes_for :performances
scope :shows_with_pending_performance, includes(:performances).where("performances.start_time >= ? ", Date.today)
end
class Performance < ActiveRecord::Base
belongs_to :show
end