rails alternative name for association one to many - ruby-on-rails-3

Simply i have table
[product_categories]
name
and
[products]
category_id
name
if i use in product model
class Product < ActiveRecord::Base
attr_accessible :...
belongs_to :product_category
end
class ProductCategory < ActiveRecord::Base
attr_accessible :...
set_table_name "product_categories"
has_many :products
end
i can fire
product = Product.new
product.product_category
but it is possible to rename that product_category for association for example
product.category
?

If you don't need to refer to the category with product.product_category and want to use only product.category do:
class Product < ActiveRecord::Base
attr_accessible :...
belongs_to :category, class_name: 'ProductCategory'
end

Related

Rails - eager load has_many :through with condition on association

Let's say I have an Item model and Category model with has_many :through association:
class Item < ActiveRecord::Base
has_many :category_items
has_many :categories, through: category_items
end
class Category < ActiveRecord::Base
has_many :category_items
has_many :items, through: category_items
end
class CategoryItems < ActiveRecord::Base
belongs_to :category
belongs_to :items
end
now, I want to have a scope on items that will get all items that are in specific status (assume it has status attribute) for specific category. for example: get all items with status "in stock" and which belongs to category with id = 3, something like:
scope :in_stock_for_category, ->(category) { where(status: SOME_ENUMERATED_VALUE) ....
i'm missing the last part of the query to limit the result set to the specific category.
Thanks!
Since you don't have a category_id column in your items table, you need to join either category_items or cateogeries in your scope before you can specify a particular category's ID condition.
class Item < ActiveRecord::Base
scope :in_stock_for_category, -> do |category|
joins(:category_items).
where(category_items: {category_id: category.id}).
where(items: {status: SOME_ENUMERATED_VALUE}).
group("items.id") # grouping might be unnecessary since you're adding the where condition for the category's id
end
end
That will work. Or if you want to join categories, do the following:
class Item < ActiveRecord::Base
scope :in_stock_for_category, -> do |category|
joins(:categories).
where(categories: {id: category.id}).
where(items: {status: SOME_ENUMERATED_VALUE}).
group("items.id") # grouping might be unnecessary since you're adding the where condition for the category's id
end
end
If you already have a category however, it might be useful to create a has_many relationship for a items that have a certain status. Something like the following:
class Category < ActiveRecord::Base
has_many :in_stock_items, -> do
where(items: {status: SOME_ENUMERATED_VALUE})
end, through: :category_items, source: :item
end
Also, if you have a status scope in Item (something like scope :in_stock, -> { where(status: SOME_ENUMERATED_VALUE) }), you can most likely change the above has_many relationship to the following:
class Category < ActiveRecord::Base
has_many :in_stock_items, -> do
merge(Item.in_stock) # http://apidock.com/rails/ActiveRecord/SpawnMethods/merge
end, through: :category_items, source: :item
end
That should tidy things up.

uninitialized constant Order::OrderItem with belongs_to in OrderItem

I have a code that once i create the order, it will automatically fill up information for the order items (because every order has many items) but i have the error uninitialized constant Order::OrderItem. How do i solve this?
Model
class Order < ActiveRecord::Base
# attr_accessible :title, :body
attr_accessible :amount, :currency
has_many :order_items
end
class OrderItems < ActiveRecord::Base
attr_accessible :items, :order_id, :quantity
belongs_to :order
end
Controller
def checkout
#order = Order.new # Create new order
#order.total = #shopping_cart.total
#order.sub_total = #shopping_cart.subtotal
#order.sales_tax = #shopping_cart.taxes
#shopping_cart.shopping_cart_items.each do |cart_item|
#orderitems = #order.order_items.build(items: cart_item.item.name, quantity: cart_item.quantity)
end
end
uninitialized constant Order::OrderItem
The problem is with this line
class OrderItems < ActiveRecord::Base
Model class names supposed to be singular.Change OrderItems to OrderItem.And also don't forget to change the model file name as well.

Rails active record query through multiple tables

I am trying to query for questions based on subject or category. I have a Category model which has many Subjects, and a Subjects model which has many Questions. How do I select 50 questions where the subject_id = x or category_id = y? I'm not sure if I need to change my model associations then query or use a query with the current associations. Here are the models (stripped of some excess code):
category.rb
class Category < ActiveRecord::Base
has_many :subjects, class_name: "Subject",
foreign_key: "category_id"
has_many :questions, through: :subjects
end
subject.rb
class Subject < ActiveRecord::Base
belongs_to :category
has_many :questions, class_name: "Question",
foreign_key: "subject_id"
end
question.rb
class Question < ActiveRecord::Base
belongs_to :subject
end
The most success I've had is with "Question.joins(:subject).group(category_id:1)", which only returns the last question with an associated category. Any suggestions? Thanks!
So you could make a scope
class Question < ActiveRecord::Base
scope :q_or_c ->(q, c){ where('category_id = ? OR question_id = ?', q, c) }
...
end
and then call it with
Question.q_or_c(question_id, category_id)

Ruby ActiveRecord has_one with conditions

Let's say I have some Items for sale, and I'm keeping track of their Cost historically:
class Cost < ActiveRecord::Base
belongs_to :item
# eg: costs.amount = 123.45; costs.item_id = 1; costs.created_at = 2011-08-11 16:28
end
class Item < ActiveRecord::Base
has_many :costs
# eg: items.id = 1; items.name = Cheese Sandwich
end
This code works, I can pull out all the previous costs for the item I'm selling.
I feel like it should be possible to have a second clause for Item so that I can pull out the current price directly:
class Item < ActiveRecord::Base
has_many :costs
has_one :current_cost, :class_name => :costs, :conditions => 'MAX(created_at)'
end
my_item.current_cost # => <£123.45, 45 minutes ago>
Any ideas how to achieve this?
class Item < ActiveRecord::Base
has_many :costs
def current_cost
self.costs.order("created_at DESC").first
end
end
my_item.current_cost
has_one :current_cost, :class_name => :costs, :order => 'create_at DESC'
You can use the scope:
class Item < ActiveRecord::Base
has_many :costs
scope :current_cost, limit(1).order("created_at DESC")
end
usage:
my_item.current_cost

Using after_create

I have a model, Category. And I want to create an new default sub_category when ever the category is created. But I'm not sure how to do it. Here is what I have.
class Category < ActiveRecord::Base
attr_accessible :title, :position
has_many :sub_categories
after_create :make_default_sub
def make_default_sub
#Sub_Categories.new( :title=>' ');
end
end
Why not to use ancestry gem? In the future if you will have more subcategories, it will be easier to manage them.
For example in your case:
class Category < ActiveRecord::Base
attr_accessible :title, :position
has_ancestry
after_create :create_default_subcategory
def make_default_sub
children = self.children.new
children.title = ''
children.position = 1 # or autogenerated
children.save!
end
end
But can you explain, why do you need such a strange default behaviour?
Thanks