【问题标题】:How do I access information from multiple associated models in the Controller in an effiecient manner?如何有效地访问 Controller 中多个关联模型的信息?
【发布时间】:2012-10-18 18:51:25
【问题描述】:

首先,一些背景。

我的应用模型是这样的:

  User has_many :subscriptions; has_many :courses, :through => :subscriptions
Subscription belongs_to :course, :user
  Course has_many :subscriptions; has_many :users, :through => :subscriptions

订阅是一个连接表,用于存储诸如状态(:active、:inactive、:failed、:passed、:unpaid)之类的信息,并用作连接课程所带来的所有信息的连接器(例如作为 Grade 模型(尚未添加)、Payment 模型(正在进行中)等)。

我想添加付款模型来存储订阅的付款历史记录。每次付款可以用于一个或多个订阅。到目前为止,我已经尝试了 Payment has_many :subscriptions,但是 我在控制器逻辑方面遇到了问题,我在想也许有更好的方法来关联“来自用户的付款”的模型订阅课程。”

从技术上讲,在支付展示操作中,我需要来自每个模型(course.name、支付用户的 user_id、payment.amount,所有这些都与订阅相关联)和支付中的信息。创建操作,我需要设置订阅的状态(我可以这样做)。

如果这是关联各种模型的一种合乎逻辑/有效的方式,我如何以最少的数据库调用在支付展示操作中访问所需的信息(来自每个模型课程、用户、支付和订阅的一些信息)?我正在使用Rails 3.2/Ruby 1.9 并希望坚持使用 ActiveRecord/ARel 而不是直接的 sql 语句。我也愿意接受“你做错了”的答案。如果更改关联可以更有效地从控制器访问表,我也愿意。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 database-design activerecord controller


    【解决方案1】:

    做(在config/routes.rb

    resources :users do
      resources :courses do
        resources :subscriptions
      end
    end
    

    这将允许你做@user.courses.subscriptions

    如果你想从courses回到users,例如,你可以修改路由为like

    resources :users, :shallow => true do
     #...
    end
    

    编辑:

    对于付款,我会照你说的做has_many :subscriptions

    当您显示付款时。你会做类似的事情

    payment_history = Payment.find(params[:id])
    @subscriptions = payment_history.subscriptions
    

    现在您有了指向该付款历史的链接的订阅列表,例如

    您将在视图中循环并显示每个订阅

    <% @subscriptions.each do |subscription|%>
      <%= subscription.payment.id %>
      <%= subscription.users.size %>
      <%= subscription.courses.size %>
      <%= subscription.paying_user.name  %> <!-- or whereever it exists-->
    <% end%>
    

    您需要确保您有一个路由并在更改路由后重新启动服务器

    resources :payments, :shallow => true do
       resources :subscriptions
    end
    

    【讨论】:

    • 感谢您的回答。我知道我是 Rails 和一般编程的新手,但我很确定路由不会生成访问数据库的方法。此外,我正在尝试遵循 rails guide on routing 中的经验法则,即“资源的嵌套深度不应超过 1 级”。我不知道:shallow 选项,并将对其进行研究。
    • 很高兴知道。我不知道1级。谢谢。编辑:阅读更多内容后,我认为在需要时有两个层次是安全的。一定是 Rails 2 的。我可能错了。
    • 确实如此。这只是一个指导方针,而不是规则。但是,路线不是问题。它们与@model.children_models 之类的方法的生成没有任何关系。这是由模型之间的关联定义的。我更新了问题以使其更加清晰,并修复了我的模型关联中的错误(对此感到抱歉)。
    • 我稍微编辑了您的答案,使其适用于我的具体情况。非常感谢您的帮助。
    • 您已编辑的答案主要回答了我的问题,但忽略了 includes(:course, :user),这是使下面的视图调用正常工作所必需的(否则,您会收到 nil::NilClass 的无方法错误)。我尝试编辑答案以包含该信息,但由于某种原因未被接受。如果您想要接受的答案,您可以添加该部分。否则,我会支持您的答案并自己添加一个来解释完整的解决方案。不管怎样,感谢大家帮我解决这个问题。
    【解决方案2】:

    @D3mon-1stVFW 的回答让我走上了解决这个问题的正确轨道。

    对于付款显示操作,查询类似于:

    @payment = Payment.find_by_id(params[:id])
    @subscriptions = @payment.subscriptions.includes(:course, :user)
    

    这样就可以访问与订阅相关的课程和用户数据,如下所示:

    <% @subscriptions.each do |subscription|%>
      <%= subscription.payment.amount %>
      <%= subscription.user.email %>
      <%= subscription.course.name %>
      <%= subscription.state  %>
    <% end%>
    

    对于还没有payment.id 的付款新建/创建操作,查询略有不同:

    @unpaid_subs = Subscription.where(:user_id => current_user.id).unpaid.includes(:course)
    @payment = Payment.new
    

    current_user 是要付款(创建新付款)的用户,.unpaidSubscription 模型上的一个范围,如下所示:

    scope :unpaid, -> { where('subscriptions.payment_id' => nil)}
    

    并且在视图中,您可以使用与显示视图相同的方式访问数据:

    <% @unpaid_subs.each do |sub| %>
      <%= sub.course.name %> | <%= sub.course.credits %><br />
    <% end %>
    

    我的主要困惑是我不知道您可以从孩子那里访问父母关联。订阅belongs_to课程,但您仍然可以订阅subscription.course.something

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-03
      相关资源
      最近更新 更多