通过多个级别的 has_many 关联渲染带有集合的部分
我正在尝试显示属于卖家产品帖子的订单集合,
买家是订单中的 user_id,卖家是产品中的 user_id
快速:
一个用户有很多产品
一个产品有多个帖子(将产品带到多个活动)
一个帖子有很多订单(其他用户可以订购)
这是我的代码
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :name, :email, :password, :password_confirmation, :remember_me,
:bio, :reason, :barter
#:email, :name, :bio, :reason, :barter, :
has_many :products, :dependent => :destroy
has_many :posts, :dependent => :destroy
has_many :orders, :dependent => :destroy
class Product < ActiveRecord::Base
belongs_to :user
belongs_to :club
belongs_to :category
has_many :posts, :dependent => :destroy
class Post < ActiveRecord::Base
belongs_to :product, :include => [:user]
belongs_to :event
has_many :orders, :dependent => :destroy
accepts_nested_attributes_for :orders
class Order < ActiveRecord::Base
belongs_to :user
belongs_to :post
#schema
create_table "orders", :force => true do |t|
t.float "quantity"
t.float "order_price"
t.integer "post_id"
t.integer "user_id"
t.boolean "payment_received"
t.integer "mark_for_buyer"
t.string "comment_for_buyer"
t.integer "mark_for_seller"
t.string "comment_for_seller"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "orders", ["post_id"], :name => "index_orders_on_post_id"
add_index "orders", ["user_id"], :name => "index_orders_on_user_id"
create_table "posts", :force => true do |t|
t.float "quantity"
t.datetime "deadline"
t.integer "product_id"
t.integer "event_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "products", :force => true do |t|
t.string "title"
t.text "desc"
t.text "ingredients"
t.float "deposit"
t.float "cost"
t.string "units"
t.float "quantity"
t.float "deadline_hours"
t.boolean "presell_option"
t.integer "user_id"
t.integer "category_id"
t.integer "club_id"
t.datetime "created_at"
t.datetime "updated_at"
end
orders/index.html.erborders
#this one works beautifully
<%= render :partial => "order", :collection => @orders.find_all_by_user_id(current_user.id), :locals => {:order => @order} %>
#this one doesn't work (has_many association resources have been tricky for me)
<%= render :partial => "order", :collection => @orders.where(:post => {:product => {:user_id => current_user.id}}) , :locals => {:order => @order} %>
/_order.html.erb
<tr>
<td><%= order.user.name %></td>
<td><%= order.post.product.user.name %></td>
<td><%= link_to order.post.product.title, order.post %></td>
<td><%= number_to_currency order.order_price %></td>
<td><%= order.quantity %></td>
<td><%= order.updated_at.to_formatted_s(:short) %> </td>
<td><%= order.payment_received %></td>
<td><%= link_to 'Show', order %></td>
<td><%= link_to 'Edit', edit_order_path(order) %></td>
<td><%= link_to 'Destroy', order, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
现在,一个集合效果很好,其中订单有一个user_id字段,它收集用户下订单并显示所有正确的订单。 另一个集合不起作用,我收到此错误:
错误
ActiveRecord::StatementInvalid in Orders#index - No attribute named `user_id` exists for table `product`
但“产品”表中有一个“user_id”字段。我可以在 cancan 中调用此方法,将订单管理限制为拥有所订购产品的用户,并且工作精美
can :update, Order, :post => {:product => {:user_id => user.id }}
任何见解都非常感谢!
I am trying to show a collection of orders that belongs to a sellers products posts
the buyer is the user_id in the order, the seller is the user_id in the product
Quickly:
A user has many products
A product has many postings (to bring products to multiple events)
A post has many orders (other users can order)
Here's my code
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :name, :email, :password, :password_confirmation, :remember_me,
:bio, :reason, :barter
#:email, :name, :bio, :reason, :barter, :
has_many :products, :dependent => :destroy
has_many :posts, :dependent => :destroy
has_many :orders, :dependent => :destroy
class Product < ActiveRecord::Base
belongs_to :user
belongs_to :club
belongs_to :category
has_many :posts, :dependent => :destroy
class Post < ActiveRecord::Base
belongs_to :product, :include => [:user]
belongs_to :event
has_many :orders, :dependent => :destroy
accepts_nested_attributes_for :orders
class Order < ActiveRecord::Base
belongs_to :user
belongs_to :post
#schema
create_table "orders", :force => true do |t|
t.float "quantity"
t.float "order_price"
t.integer "post_id"
t.integer "user_id"
t.boolean "payment_received"
t.integer "mark_for_buyer"
t.string "comment_for_buyer"
t.integer "mark_for_seller"
t.string "comment_for_seller"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "orders", ["post_id"], :name => "index_orders_on_post_id"
add_index "orders", ["user_id"], :name => "index_orders_on_user_id"
create_table "posts", :force => true do |t|
t.float "quantity"
t.datetime "deadline"
t.integer "product_id"
t.integer "event_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "products", :force => true do |t|
t.string "title"
t.text "desc"
t.text "ingredients"
t.float "deposit"
t.float "cost"
t.string "units"
t.float "quantity"
t.float "deadline_hours"
t.boolean "presell_option"
t.integer "user_id"
t.integer "category_id"
t.integer "club_id"
t.datetime "created_at"
t.datetime "updated_at"
end
orders/index.html.erb
#this one works beautifully
<%= render :partial => "order", :collection => @orders.find_all_by_user_id(current_user.id), :locals => {:order => @order} %>
#this one doesn't work (has_many association resources have been tricky for me)
<%= render :partial => "order", :collection => @orders.where(:post => {:product => {:user_id => current_user.id}}) , :locals => {:order => @order} %>
orders/_order.html.erb
<tr>
<td><%= order.user.name %></td>
<td><%= order.post.product.user.name %></td>
<td><%= link_to order.post.product.title, order.post %></td>
<td><%= number_to_currency order.order_price %></td>
<td><%= order.quantity %></td>
<td><%= order.updated_at.to_formatted_s(:short) %> </td>
<td><%= order.payment_received %></td>
<td><%= link_to 'Show', order %></td>
<td><%= link_to 'Edit', edit_order_path(order) %></td>
<td><%= link_to 'Destroy', order, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
Now, one collection works great, where the order has a user_id field, it collects the user that made the order and shows all the correct orders.
The other collection doesn't work, and I'm getting this error:
Error
ActiveRecord::StatementInvalid in Orders#index - No attribute named `user_id` exists for table `product`
But there IS a 'user_id' field in the 'product' table. I am able to call this in cancan to limit management of orders to the user who owns the product that is ordered, and works beautifully
can :update, Order, :post => {:product => {:user_id => user.id }}
Any insight is much appreciated!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
查看德墨忒尔定律。它解释了为什么你正在做的事情会导致问题(没有关注点分离=意大利面条式代码)。另请查看 ActiveSupport::Delegate了解如何将 Demeter 定律简洁地应用到 Rails 应用程序中,并避免使用无聊的 getter 和 setter 列表。
一些可以帮助您的注意事项:
where
。您的视图应该具有数组(或 ActiveSupport::Proxy 的)来简单地迭代和显示。您应该避免让视图触发数据库查询,并且永远不应该在其中保留记录获取业务逻辑。@comment.post_title
(注意下划线),而不是@comment.post.title
。这避免了要求您的视图具有数据库架构和模型关联的固有知识。它只需要知道评论有帖子标题,但数据是建模的。如果您重构代码,使每个模型专注于单一关注点并对单一资源进行建模,然后以干净、划分的方式将关联分层,那么您肯定会不需要有人为您解决这个单一问题(授人以渔……)。
Check out the Law of Demeter. It explains why what you're doing is causing problems (no separation of concerns = spaghetti code). Also check out ActiveSupport::Delegate to see how you can concisely apply the Law of Demeter to your Rails app and avoid lists of boring getters and setters.
A few notes to help you out:
where
in your controller. Your view should have arrays (or ActiveSupport::Proxy's) to simply iterate over and display. You should avoid having your view trigger database queries, and you should never keep record-fetching business logic in them.@comment.post.title
, define and use@comment.post_title
instead (note the underscore). This avoids requiring your view to have innate knowledge of your database schema and model associations. It simply needs to know that a comment has a post title, however that data is modeled.If you refactor your code to keep each model focused on a single concern and modeling a single resource, then layer the associations on top of that in a clean, compartmentalized fashion, you will surely obviate the need for someone to solve this single question for you (teach a man to fish…).
我发现诀窍是这个 gem http://rubygems.org/gems/nested_has_many_through 可以做到像这样的东西:
这极大地简化了我的查询和集合。
这就是我最终需要的所有代码。我听说 gemnested_has_many_through 将成为 Rails 3.1
用户模型
OrdersController
订单索引
中的标准,这将使用最少的代码通过关系返回深层嵌套数据。我当然希望它有效,但至少我的理智不受影响!
I've found the trick is this gem http://rubygems.org/gems/nested_has_many_through which can do something like this:
This has super-simplified my queries and collections.
This is all the code I ended up needing. I'm told the gem nested_has_many_through will be standard in Rails 3.1
User model
OrdersController
Orders index
This returns the deep nested data via relationships using minimal code. I sure hope its efficient, but at least my sanity is spared!