Reputation: 1930
I'm having a bit trouble with the namespaces in Rails 4.
I have ActiveRecord models Shop
, Order
, and OrderItem
# model/shop.rb
class Shop < ActiveRecord::Base
# model/order.rb
class Order < ActiveRecord::Base
has_many :order_items
# model/order_item.rb
class OrderItem < ActiveRecord::Base
belongs_to :orderable, polymorphic: true
belongs_to :order
I'm replicating the relationship between Order
and OrderItem
in a namespace like this
# model/shop/order.rb
class Shop::Order
attr_accessor :order_items
def initialize
self.order_items = []
self.order_items << Shop::OrderItem.new
end
# model/shop/order_item.rb
class Shop::OrderItem
attr_accessor :orderable_type, :orderable_id
def initialize(params = {})
if params
self.orderable_type = params['orderable_type'] if params['orderable_type']
self.orderable_id = params['orderable_id'] if params['orderable_id']
end
end
def price
orderable.price
end
def orderable
orderable_type.constantize.find_by(id: orderable_id)
end
def to_h
Hash[
orderable_type: self.orderable_type,
orderable_id: self.orderable_id,
price: self.price
]
end
end
So my problem is that when I initialize Shop::Order.new
, sometimes its order_items
is an array of OrderItem
s instead of Shop::OrderItem
s, and when I test it in the controller, if I type Shop::OrderItem
, it will return OrderItem
.
I'm wondering if Shop::OrderItem
wasn't initialized before OrderItem
and cause the issue?
Upvotes: 0
Views: 745
Reputation: 9692
You are running into a namespace collision. Depending on where the code is executing, Shop
could be the ActiveRecord model that you've defined in models/shop.rb
, or it could be the module namespace that you've defined under models/shops/*.rb
. Not only will this cause unpredictable execution, it's also confusing to read.
I recommend using a module namespace other than "Shop". Even calling it "MyShop" would be an improvement. However you'll probably still run into naming collisions between Shop
and MyShop::Shop
. You should probably rename the Shop class under the MyShop module to avoid this:
For example:
# model/my_shop/my_order.rb
class MyShop::MyOrder
# ...
end
# model/my_shop/my_order_item.rb
class MyShop::MyOrderItem
# ...
end
Having said all that, I feel like you're setting yourself up for a world of hurt. This problem might be better solved using service objects. Google up "Rails Service Objects" for some really good examples.
Upvotes: 1