How to update nested resources Rails 4 - ruby-on-rails-4

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

Related

Rails includes with has_many through giving avoid eger loading n+1 by bullet gem

My Models are like:
class ThreeDModel < ApplicationRecord
has_many :three_d_model_animations
has_many :animations, through: :three_d_model_animations
has_many :three_d_model_images, dependent: :destroy
has_many :three_d_garments
has_one :model_efm
has_one :model_edm
end
2nd:
class ThreeDModelAnimation < ApplicationRecord
belongs_to :animation
belongs_to :three_d_model
validates_presence_of :animation_file
#validates_presence_of :motion
mount_uploader :animation_file, ThreeDModelAnimationUploader
enum animation_motions: {
'Run': 'run',
'Turn Aroun (100 Frames)': 'turn_around_100_frames',
'Turn Around (300 Frames)': 'turn_around_300_frames',
'Walk (58 Frames)': 'walk_58_frames',
'Walk (92 Frames)': 'walk_92_frames'
}
end
3rd:
class Animation < ApplicationRecord
has_many :three_d_model_animations
has_many :three_d_models, through: :three_d_model_animations
mount_uploader :video, AnimationVideoUploader
validates_presence_of :video
validates :name, :frames, :loop_start, :loop_end, presence: true
end
Now my query is:
#model = ThreeDModel.where(id: params[:id]).includes(:model_efm, :model_edm, :three_d_model_images, :three_d_model_animations, :animations).last
which gives the following message by the bullet gem:
AVOID eager loading detected
ThreeDModel => [:three_d_model_animations, :animations]
is there a better way so that n+1 could be avoided. Thanks in advance

Link models through acts_as_taggable_on rails

I have a model Product which has_many :taxons, through: :classifications. How to implement acts_as_taggable_on to implement the tagging of products with the names of taxons instead of the the tags from the tag table? Is it possible or not?
#app/models/product.rb
class Product < ActiveRecord::Base
translates :name
accepts_nested_attributes_for :translations, allow_destroy: true, reject_if: :all_blank
# Associations
has_many :classifications, inverse_of: :product, dependent: :delete_all
has_many :taxons, through: :classifications
end
#app/models/classification.rb
class Classification < ActiveRecord::Base
self.table_name = 'products_taxons'
# Associations
belongs_to :product, inverse_of: :classifications
belongs_to :taxon, inverse_of: :classifications, touch: true
end
#app/models/taxon.rb
class Taxon < ActiveRecord::Base
translates :name
globalize_accessors
has_many :classifications, inverse_of: :taxon, dependent: :delete_all
has_many :products, through: :classifications
end

Rails Counter Cache On the same model?

I have a model Task, and each task has_many other tasks:
Class Task < ActiveRecord::Base
belongs_to :sub_task, class_name: Task.name, touch: true
has_many :sub_tasks, class_name: Task.name, foreign_key: :sub_task_id, dependent: :destroy
end
Can I add a counter cache to the number of sub_tasks each task has? How?
Yes you can add the counter cache.
class Task < ActiveRecord::Base
belongs_to :sub_task, class_name: Task.name, touch: true, counter_cache: :sub_tasks_count
has_many :sub_tasks, class_name: Task.name, foreign_key: :sub_task_id, dependent: :destroy
end
You need to create a migration to add a new column named sub_tasks_count to the Tasks table.
There's no need for doing what #Rubysmith wrote, you can just:
class Task < ActiveRecord::Base
belongs_to :task, counter_cache: true
has_many :tasks, dependent: :destroy
end
Migration:
class AddTaskCounterToTasks < ActiveRecord::Migration
def change
add_column :tasks, :tasks_count, :integer, default: 0, null: false
end
end

Rails 4: how to use form_for (has_many :through with extra attributes)

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

Add items to a has_many relation on creation

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