I can't delete nested attributes child record.
Article with Article_series is the model.
Here's the code.
Model
class Article < ApplicationRecord
has_many :articles_article_series
has_many :article_series, through: :articles_article_series
accepts_nested_attributes_for :articles_article_series, allow_destroy: true, reject_if: proc { |attributes| attributes['article_id'].blank? && attributes['series_id'].blank? && attributes['num'].blank? }
Controller
def update
#article = Article.find(params[:article][:id])
# article_series delete
#article.articles_article_series.each do |series|
series.mark_for_destruction
end
#article.save
Does anyone tell me why & how?
I believe you may be looking for
has_many :articles_article_series, dependent: :destroy
It looks like only array works 'mark_for_destruction'.
#article.articles_article_series.to_a.first.mark_for_destruction
Before, I did like below. It's so difficult to find the way to fix.
#article.articles_article_series.first.mark_for_destruction
Thanks for all contributes :)
Related
Have below association in author class
has_many :books,
class_name :"Learning::Books",
through: :elearning,
dependent: :destroy
with after_commit as,
after_commit :any_book_added?, on: :update
def any_book_added?
book = books.select { |book| book.previous_changes.key?('id') }
# book's previous_changes is always empty hash even when newly added
end
Unable to find the newly added association with this method. Is this due to class_name?
Rails has a couple methods that might help you, before_add and after_add
Using this, you can define a method to set an instance variable to true
class Author < ApplicationRecord
has_many :books, through: :elearning, after_add: :new_book_added
def any_book_added?
#new_book_added
end
private
def new_book_added
#new_book_added = true
end
end
Then when you add a book to an author, the new_book_added method will be called and you can at any future time ask your Author class if any_book_added?
i.e.
author = Author.last
author.any_book_added?
=> false
author.books = [Book.new]
author.any_book_added?
=> true
As you can see, the callback method new_book_added can accept the book that has been added as well so you can save that information.
I am having a model Evaluation that has many sub evaluations (self refential)
class Evaluation < ApplicationRecord
has_many :sub_evaluations, class_name: "Evaluation", foreign_key: "parent_id", dependent: :destroy
before_save :calculate_score
def calculate_score
# do something
end
end
I am creating and updating evaluation with sub evaluations as nested attributes.
calculate_score method is triggered on sub evaluation creation but not while updating. I have tried before_update and after_validation. But nothing seems to be working.
Evaluation form
= form_for #evaluation do |f|
...
= f.fields_for :sub_evaluations do |sub_evaluation|
...
What seems to be the issue?
This article helped me to fix the issue.
Child callback isn't triggered because the parent isn't "dirty".
The solution in the article is to "force" it to be dirty by calling attr_name_will_change! on a parent attribute that, in fact, does not change.
Here is the updated model code:
class Evaluation < ApplicationRecord
has_many :sub_evaluations, class_name: "Evaluation", foreign_key: "parent_id", dependent: :destroy
before_save :calculate_score
def calculate_score
# do something
end
def exam_id= val
exam_id_will_change!
#exam_id = val
end
end
See Active Model Dirty in the Rails API
Let's say I have a model Book
class Books < ActiveRecord::Base
belongs_to :library
has_many :pages
validates :library_id, presence: true
end
And a model Library
class Library < ActiveRecord::Base
has_many :books
belongs_to :city
end
How can I fix a nil exception I'm getting somewhere, NoMethodError undefined method library for nil:NilClass when I do something like book.library?
Or in other words how can I make sure that before linking a book to a library, the library_id is not nil and it exists in the database? Shouldn't the validates :library_id, presence: true solve this already?
You have validated library_id. That's enough for books.
What you need to do is making sure libraries which have books can not be deleted.
Here is an example:
def destroy
#library = Library.find params[:id]
if #library.books.blank?
#library.destroy
redirect_to libraries_path
else
redirect_to library_path(#library)
end
end
Before calling book.library do a check book.library if book.library
Or add dependent destroy to Book model has_many :books, dependent: :destroy
Before you calling book.library ,yous hould do a check on book :
book.library if book
I have a problem.
I have a Content model that has a polymorphic association, Sponsorship.
In my content form I have a nested form with some sponsorship details. These sponsorship details aren't mandatory, but now every time that I edit a content the sponsorship table is filled with blank data.
I will simplify my code here:
class Content < ActiveRecord::Base
include Sponsorable
end
class Sponsorship < ActiveRecord::Base
belongs_to :sponsorable, polymorphic: true
end
module Sponsorable
extend ActiveSupport::Concern
included do
has_one :sponsorship, as: :sponsorable
accepts_nested_attributes_for :sponsorship
end
end
I need to clarify that I create an auto-saving feature on my content model, so in my content controller I put a Content.create in the "new" method.
def new
#content = Content.create(author: current_user)
redirect_to edit_admin_content_path(#content)
end
And to fill the sponsorship detail
def edit
content.build_sponsorship unless content.sponsorship
end
Every time I create and save a content the sponsorship details are created also if I leave the form fields empty. My content table has a boolean "sponsor": is there a way to save association only if sponsor == true?
You may want to look at the reject_if: option for accepts_nested_attributes_for:
accepts_nested_attributes_for :sponsorship, reject_if: proc { |attributes| attributes['title'].blank? }
Looking up other questions on this matter seem to confirm this.
--
There is also reject_if: :all_blank -
accepts_nested_attributes_for :sponsorship, reject_if: :all_blank
I am trying to modify nested attributes before they are saved in my database. The idea is that if someone has already submitted a costume with a given cid in the costume database, we should pull that one and use it for the current agreement. However, through debugging, I've found that the nested attributes array doesn't change at all. Any thoughts?
Thanks!
Matt
app/models/agreement.rb
class Agreement < ActiveRecord::Base
before_save :get_costumes
has_and_belongs_to_many :costumes, join_table: :agreement_costumes
accepts_nested_attributes_for :costumes, reject_if: proc { |attributes| attributes['cid'].blank? }
has_many :drycleans
accepts_nested_attributes_for :drycleans, allow_destroy: true, reject_if: :all_blank
def get_costumes
self.costumes.map! { |costume|
unless Costume.where(cid: costume.cid).nil?
Costume.where(cid: costume.cid).first
end
}
end
end
Your unless-condition is never true. With a where-statement you get always an ActiveRecord. And also a empty ActiveRecord is not nil.
Try to change that condition to:
unless Costume.where(cid: costume.cid).count == 0
Or to:
unless Costume.find_by_cid(costume.cid).nil?