I trying to create a nested form with N models associated.
This is the schema:
and I need a Edit-Form which iterate through all objects till the last one:
My delivery object looks like this:
class Delivery < ActiveRecord::Base
has_many :boxes
and this is the box object
class Box < ActiveRecord::Base
belongs_to :box, :polymorphic => true, :inverse_of => :box
has_many :boxes
accepts_nested_attributes_for :boxes
In the deliveries controller :
def new
#delivery = Delivery.new
# if you want 3 instantiated objects
3.times { #delivery.boxes.build }
end
Related
I have two models with a has_many to has_many relationship through a join table.
class Article < ActiveRecord::Base
has_many :authorings, -> { order(:position) }, :dependent => :destroy
has_many :authors, through: :authorings
end
class Author < ActiveRecord::Base
has_many :authorings, -> { order(:position) }
has_many :articles, through: :authorings
end
class Authoring < ActiveRecord::Base
belongs_to :author
belongs_to :article
acts_as_list :scope => :author
end
The getter and setter methods for the array
def author_list
self.authors.collect do |author|
author.name
end.join(', ')
end
def author_list=(author_array)
author_names = author_array.collect { |i|
i.strip.split.each do |j|
j.capitalize
end.join(' ') }.uniq
new_or_found_authors = author_names.collect { |name| Author.find_or_create_by(name: name) }
self.authors = new_or_found_authors
end
I want to maintain the order of the list of authors that get saved to the model. That is, I would like to be able to change and reorder the author_list and have it retrieved in that order for the view. I want to be to change it ['foo','bar'] or ['bar','foo']. How can I do this?
As a note, I have tried using acts_as_list and added a position column to the database for authoring but to no success.
You need to have a position attribute for each author.
Then you can generate a sorted activerecord array and grab the name attribute
authorlist = Author.order(:position).pluck(:name)
I'm not seeing how you're changing the position attribute, I'm guessing you need some sort of js on the frontend to do that.
I recently migrated from Rails 3 to Rails 4 and in the process I noticed that sorting association does not work in Rails 4. Following are the sample models:
#box.rb
class Box < ActiveRecord::Base
has_many :items
accepts_nested_attributes_for :items, :allow_destroy => true
before_validate
items.sort! { <some condition> }
end
end
#item.rb
class Item < ActiveRecord::Base
belongs_to :box
end
In Rails 3, sort! method on the association modified the items hash, but in Rails 4 it returns a new sorted instance but does not modify the actual instance. Is there a way to overcome this?
Try this:
#box.rb
class Box < ActiveRecord::Base
has_many :items
accepts_nested_attributes_for :items, :allow_destroy => true
before_validate
self.items = items.sort { <some condition> }
end
end
#item.rb
class Item < ActiveRecord::Base
belongs_to :box
end
Sorting before storing won't really help. When you pull them from the database they might not be in that order. You wan't to specify the order on the has many (or in the item model).
If you have a more complicated ordering, then please post that logic.
class Box < ActiveRecord::Base
# Can replace position with hash like: { name: :asc }
has_many :item, -> { order(:position) }
accepts_nested_attributes_for :items, :allow_destroy => true
before_validate
items.sort! { <some condition> }
end
end
I have Vehicles, each can have many bookings. Each Booking can have many Events. This question comes as I validate a new Booking and Event against an existing Vehicle.
When validating the Event model I need to traverse up to the Vehicle and find all the Bookings and any Events that may clash with the new one, before I've actually saved the new Booking and Event.
Class Event < ActiveRecord::Base
belongs_to :eventable, :polymorphic => true
end
Class Booking < ActiveRecord::Base
belongs_to :vehicle
has_many :events, :as => :eventable
end
Class Vehicle < ActiveRecord::Base
has_many :bookings
end
When creating the Booking it has vehicle_id. How can I get the vehicle_id inside the Event model?
You would normally use validates_uniqueness_of with a :scope, but the join association here won't work that way. Here's an example of a custom uniqueness validator:
class Booking
# Create a custom validation
validate :verify_unique_vehicle_date
private
def verify_unique_vehicle_date
if booking = Booking.includes(:events).where('vehicle_id = ? AND events.date IN (?)', self.vehicle_id, self.events.map(&:date)).first
errors.add(:vehicle, "already booked on #{booking.events.map(&:date).join(',')}")
end
end
end
I am currently trying to create a custom method on a model, where the conditions used are those of a has_many association. The method I have so far is:
class Dealer < ActiveRecord::Base
has_many :purchases
def inventory
inventory = Vehicle.where(:purchases => self.purchases)
return inventory
end
end
This is not working, due to the fact that Vehicle has_many :purchases (thus there is no column "purchases" on the vehicle model). How can I use the vehicle.purchases array as a condition in this kind of query?
To complicate matters, the has_many is also polymorphic, so I can not simply use a .join(:purchases) element on the query, as there is no VehiclePurchase model.
EDIT: For clarity, the relevant parts of my purchase model and vehicle models are below:
class Purchase < ActiveRecord::Base
attr_accessible :dealer_id, :purchase_type_id
belongs_to :purchase_item_type, :polymorphic => true
end
class Vehicle < ActiveRecord::Base
has_many :purchases, :as => :purchase_item_type
end
class Dealer < ActiveRecord::Base
def inventory
Vehicle.where(:id => purchases.where(:purchase_item_type_type => "Vehicle").map(&:purchase_item_type_id))
end
end
Or:
def inventory
purchases.includes(:purchase_item_type).where(:purchase_item_type_type => "Vehicle").map(&:purchase_item_type)
end
I was able to do this using the :source and :source_type options on the Vehicle model, which allows polymorphic parents to be associated.
How can I delete nested objects in a form? I found out that I need to add :allow_destroy in the parent model at the accepts_nested_attributes_for directive.
Further, I want to restrict the deletion. A nested object only should be deleted, if the parent object is the only one that retains the association.
Example:
class Internship < ActiveRecord::Base
belongs_to :company
accepts_nested_attributes_for :company, allow_destroy => true
end
class Company < ActiveRecord::Base
has_many :internships
end
Explanation: A company can host many internships. Therefore, I do not want to delete the company record as long as there is at least one other internship associated with it.
You could use dependent => :destroy
class Internship < ActiveRecord::Base
belongs_to :company
accepts_nested_attributes_for :company, allow_destroy => true
end
class Company < ActiveRecord::Base
has_many :internships, :dependent => :destroy
end
If you return false in a before_destroy filter, then the destroy action will be blocked. So we can check to see if there are any internships associated to the company, and block it if so. This is done in the company model.
class Company < ActiveRecord::Base
has_many :internships
before_destroy :ensure_no_internships
private
def ensure_no_internships
return false if self.internships.count > 0
end
end