Error on updating nested attributes in rails - ruby-on-rails

Three models:
class Order < ActiveRecord::Base
belongs_to :product
belongs_to :sale
end
class Sale < ActiveRecord::Base
has_many :orders
accepts_nested_attributes_for :orders, :reject_if => :all_blank
end
class Product < ActiveRecord::Base
belongs_to :greenhouse
has_many :orders
end
First a product is created. Then, an order can be made with one Product. Then, what I expect to be is, the Sale is filled with many Orders. But, when saving the Sale, it only ignores the Orders attached.
I've only found examples when the Sale creates the Order, or the parent object creates the Child object, but in this case, the child object, or the Order is already created, and only needs to be assigned or related with the new Sale.
How can I relate the child object with a new parent?

Just be sure that you have permit params at your SalesController something like this:
params.require(:sale).permit(:each, :sale, :field, :as, :symbol, :and, orders_attributes: [:each, :order, :field, :as, :symbol])
This is the most common issue which gives the described behavior. If not, we need some more information.

Related

Is: grandparent.parents.children association chaining not correct in Rails 4?

I'm having trouble figuring out the proper way of retrieving all children of multiple parents through association chaining.
To simplify I have three models:
class Customer < ActiveRecord::Base
has_many :invoices
end
class Invoice < ActiveRecord::Base
belongs_to :customer
has_many :line_items
end
class LineItem < ActiveRecord::Base
belongs_to :invoice
end
After creating a few objects I tired to use the example from rails guides (association basics: 4.3.3.4 includes):
Customer.first.invoices.line_items
It returns:
undefined method `line_items' for #<Customer::ActiveRecord_Associations_CollectionProxy
Is grandparent.parents.children not usable?
EDIT
I'm not searching for the grandparent.parents.first.children, but all children of all parents in the collection, rails guides state:
If you frequently retrieve line items directly from customers (#customer.orders.line_items),
As a valid operation, I would like to know if that is a mistake.
FINAL As stated in the comments of the selected answer: in ActiveRecord: scopes are chainable but associations are not.
The customer.invoices.line_items cannot work the way you want to, since the has_many always is linked to a single record. but you can achieve what you want (if I understand correctly) using has_many through
as follows:
class Customer < ActiveRecord::Base
has_many :invoices
has_many :line_items, through: :invoices
end
class Invoice < ActiveRecord::Base
belongs_to :customer
has_many :line_items
end
class LineItem < ActiveRecord::Base
belongs_to :invoice
end
and now you can write:
customer.line_items
and it will return all line_items which are connected to a customer's invoices.
Customer.first.invoices.first.line_items
Or if you want all of the data together, you can do something like:
results = Customer.first.invoices.includes(:line_items)
Then you may access data with no DB call, by looping results. For first data ex: results.first.line_items
Hope it helps!
Customer.first.invoices will return an collection (like an array) of invoices. The line_items method isn't defined for a collection, but its defined for an invoice. Try Customer.first.invoices.first.line_items
EDIT - If you always want the orders to include the line items, you can just do:
class Customer < ActiveRecord::Base
has_many :orders, -> { includes :line_items }
end
class Order < ActiveRecord::Base
belongs_to :customer
has_many :line_items
end
class LineItem < ActiveRecord::Base
belongs_to :order
end

Database creation/saving with a many-to-many relationship

I have two tables, item and category, and a joined table named Items_Categories. The one restriction I have is that an item HAS to have a category.
In my Item Model, I have this code:
class Item < ActiveRecord::Base
has_many :items_categories
has_many :categories, through: :items_categories
has_many :item_orders
has_many :orders, through: :item_orders
even though categories is not a column in my Items database.
Here's my ItemsCategory model:
class ItemsCategory < ActiveRecord::Base
belongs_to :item
belongs_to :category
end
Here's my Category Model:
class Category < ActiveRecord::Base
has_many :items_categories
has_many :items, through: :items_categories
end
In my test, I have this issue:
test 'it is valid' do
category = Category.create(name: "hot beverages")
item = category.items.create(title: "fjdkasf", description: "fjakdsf", price: 20901290)
assert item.valid?
end
Basically, this test fails because I cannot create an item until it item.categories is not nill. But the validation doesn't pass until I create the item in item_categories. So... what do I do? Basically I can't pass the validation when I create the item because the item doesn't yet have a category. But I want to make sure that every time I create an item, it has an associated item. So what do I do?
Validation with has_many :through relations can be tricky sometimes, there's a hint in the has_many :through documentation that you should define the inverse_of attribute on your join model:
If you are going to modify the association (rather than just read from
it), then it is a good idea to set the :inverse_of option on the
source association on the join model. This allows associated records
to be built which will automatically create the appropriate join model
records when they are saved. (See the 'Association Join Models'
section above.)
class ItemsCategory < ActiveRecord::Base
belongs_to :item, inverse_of: :items_categories
belongs_to :category, inverse_of: :items_categories
end
To be honest, I'm not 100% sure this will fix it, but give it a try and report back.

Rails ActiveRecord model association

I have a User model and a product model.
User has_many :products, :dependent => :destroy
Product belongs_to :user, :foreign_key => "user_id", touch: true
I want to create a wishlist for every user.
So i have to create a wishlist model with proper association.
But i don't know how to start.
I presume that the wishlist model contain an id, user_id and product_id field
Do i have to use has_many through association or a has_and_belongs_to_many ?
I also want that if a user is destroyed to destroy his wishlist.
What is the best way to do?
Many thanks!
As #JZ11 pointed out, you shouldn't be linking a Product directly to a User (unless a User actually 'owns' a product for some reason). However, what was missed is the model that makes up a Wishlist item:
class User < ActiveRecord::Base
has_many :wishlists # or has_one, depending on how many lists a User can have...
end
class Product < ActiveRecord::Base
has_many :wishlist_items
end
class Wishlist < ActiveRecord::Base
belongs_to :user
has_many :wishlist_items
has_many :products, :through => :wishlist_items
end
class WishlistItem < ActiveRecord::Base
belongs_to :product
belongs_to :wishlist
end
Naturally, you should be adding :dependent => :destroy where necessary.
You don't need the has_many :products relationship on User.
I don't think it makes sense for User and Product to be linked outside of a Wishlist.
class Wishlist < ActiveRecord::Base
has_many :products
belongs_to :user
end
class User < ActiveRecord::Base
has_one :wishlist, dependent: :destroy
end
class Product < ActiveRecord::Base
belongs_to :wishlist
end
To create your join table, do:
rails g migration create_products_users_table
Once you've done that, you need to add some code, below, to create the fields in the join table. Notice the :id => false, because you do not need an id in the join table:
class CreateProductsUsersTable < ActiveRecord::Migration
def change
create_table :products_users, :id => false do |t|
t.references :product
t.references :user
end
add_index :products_users, [:product_id, :user_id]
add_index :products_users, :user_id
end
end
The code above also creates some indexes and ensures that you don't have duplicates even at the database level.
Your models would then have to look like this:
class Product < ActiveRecord::Base
has_and_belongs_to_many :users
end
class User < ActiveRecord::Base
has_and_belongs_to_many :products
end
When you destroy a user correctly, like user.destroy and not just delete it (there is a difference), then the related rows in the join table will be deleted as well. This is built in to ActiveRecord.
Notice though, that doing this will not really let you use the join table. It will accept code like user.products = [product1, product2] etc, and other goodies, but no real use of a wish list.
If you do want to use a wish list, you will have to create and use the middle join table differently, using has_many :through (I didn't check PinnyM's answer but that might be the way to do it).

How do I handle using 1 model to belong_to 2 different models at different times?

I am creating a Shopping Cart.
So I will have a model called LineItem.
Each instance of a cart will have 1+ line items. As will a completed transaction - which becomes an 'order'.
So, in theory, a LineItem belongs_to Cart and also belongs_to Order.
But, what would the DB table look like? a cart_id and order_id in my LineItems table?
That would mean that for every valid cart record, there will be an order_id that is nil (or empty). Likewise, for every valid order, there will be an empty cart_id.
This seems like a non-Railsy way to do this.
What is the best way to do this? A polymorphic association? What would that look like if I should do that?
The line item model can have two belongs_to associations
class LineItem < ActiveRecord::Base
belongs_to :cart
belongs_to :order
end
But this can get messy if it needs to belong to several different classes. The solution is polymorphic association which allows a model to belong to more than one model on a SINGLE association, which in the example below is :line_itemable. It will add two attributes, line_itemable_id and line_itemable_type to the LineItem model.
class LineItem < ActiveRecord::Base
belongs_to :line_itemable, :polymorphic => true
end
class Order < ActiveRecord::Base
has_many :line_items, :as => :line_itemable
end
class Cart < ActiveRecord::Base
has_many :line_items, :as => :line_itemable
end
If cart and order share similar attributes such as cost, then another option is to eliminate the order class and simply add a :paid flag on the cart.
I would suggest polymorphic association.
class LineItem < ActiveRecord::Base
belongs_to :owner, :polymorphic => true
end
class Order < ActiveRecord::Base
has_many :line_items, :as => :owner
end
class Cart < ActiveRecord::Base
has_many :line_items, :as => :owner
end
you will need to add owner_type and owner_id to line_items table.
Refer this

has_many with foreign key in own table as an array?

I'm trying to do a "ecommerce like" solution. When a product is defined, there are many option_values, e.g. whip cream => yes.
When I'm creating a line_item, my associations are like this.
class LineItem < ActiveRecord::Base
belongs_to :cart
belongs_to :order
belongs_to :product
belongs_to :shop
...
When a user chooses a product, he chooses options_values and a line_item must be created to store this.
Currently I'm not sure what is a good way to model the option_values in a line item.
My gut instinct is that a line_item has_many option_values, but it would seem weird to store foreign keys in option_values. The other thought is that line_item habtm option_values.
What would be a good way to model this line_item has_many option_values relationship, ideally storing the reference in the line_items table?
If your option_values are always boolean (whip cream => yes) you should have an OptionValues model with all available option_values and do habtm between LineItem and OptionValues.
If your option values are not always boolean (sugar => 2.spoons) then you must store this value (2.spoons) in the join model, so you should do something like this:
class LineItem < ActiveRecord::Base
has_many :line_item_option_values
...
end
class LineItemOptionValue < ActiveRecord::Base
belongs_to :line_item
belongs_to :option_value
end
class OptionValue < ActiveRecord::Base
has_many :line_item_option_values
end
And have the table for LineItemOptionValue a field for the value of the option.

Resources