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?
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.