mysql - 在 Rails 中将 3 个模型连接在一起以在迭代一个模型的 View 中显示

标签 mysql ruby-on-rails ruby-on-rails-3 activerecord

我有一个相当标准的“has_many :x, :through => :y”与用户、问题和充当两者之间关联的 completed_problem 的关系:

/models/user.rb

class User < ActiveRecord::Base
  has_many :completed_problems
  has_many :problems, :through => :completed_problems    
end

/models/problem.rb

class Problem < ActiveRecord::Base
  belongs_to :wall
  has_many :completed_problems
  has_many :users, :through => :completed_problems    
end

/models/completed_problem.rb

class CompletedProblem < ActiveRecord::Base
  belongs_to :user
  belongs_to :problem

  validates_presence_of :user
  validates_presence_of :problem
end

我的问题是每个模型中的数据都会影响显示。我希望在每面墙上显示一个问题列表,并针对该列表中要使用或显示的每个问题:

  • 问题.id
  • 问题名称
  • 当前用户上次完成问题的时间
    • 如果没有登录用户,一些文本
    • 如果用户还没有完成那个问题,一些其他的文本

View 中的(非常难看的)第一次传递如下:

/views/walls/show.html.erb

<% @wall.problems.each do |problem| %>
    <a id=<%= "problem_#{problem.id}" %>>
      <h3><%= problem.name %></h3>
      <p><%= "#{time_ago_in_words(problem.last_complete_by_user(current_user))} ago" if current_user && problem.last_complete_by_user(current_user) %></p>
    </a>
  </li>
<% end %>

我已经覆盖了它,但是 problem.last_complete_by_user(在上面的片段中看到)试图使用问题对象来查找所有相关的 completed_problems,以 user 作为参数,以便识别'updated_at ' 该特定问题和用户最近更新的 completed_problem 的值。

当然这并不理想,因为它将是列表中每个项目的单独查询 - 我假设首选解决方案是墙上 Controller 或模型中的一种方法,它连接所有 3 个表并返回一个新的 View 迭代的数组。不幸的是,我在 :join、:include 和 :find_by_sql 之间徘徊了太久,没有解决方案。

至少有人可以引导我朝着正确的方向前进,让这个 View 正常工作吗?

最佳答案

这就是我解决问题的方法。它可能不是最有效的解决方案,但它很干净并且在时机成熟时易于重构。我还没有尝试过代码,但它可能不会太远。如果你走这条路并遇到性能问题,我会在添加一堆疯狂的 SQL 之前研究片段缓存。

模型:

class User < ActiveRecord::Base
  has_many :completed_problems
  has_many :problems, :through => :completed_problems

  # Finds the last completed problem
  def last_completed_problem(problem)
    problems.order('created_at DESC').where(:problems => {:id => problem}).limit(1).first
  end
end

# No Changes
class Problem < ActiveRecord::Base
  belongs_to :wall
  has_many :completed_problems
  has_many :users, :through => :completed_problems
end

# No changes
class CompletedProblem < ActiveRecord::Base
  belongs_to :user
  belongs_to :problem

  validates_presence_of :user
  validates_presence_of :problem
end

app/controllers/walls_controller.rb:

class WallsController < Application::Controller
  def show
    @wall = Wall.find(params[:id]).includes(:problems)
  end
end

app/helpers/wall_helper.rb:

module WallHelper
  def show_last_completed_problem_for_user(user, problem)
    return "You are not logged in" if current_user.nil?

    completed = user.last_completed_problem(problem)

    return "You have not completed this problem" if completed.nil?

    time_ago_in_words(completed.created_at)
  end
end

app/views/walls/show.html.erb:

<%= render :partial => 'problem', :collection => @wall.problems %>

app/views/walls/_problem.html.erb:

<li>
  <a id=<%= "problem_#{problem.id}" %>>
    <h3><%= problem.name %></h3>
    <p><%= show_last_completed_problem_for_user(current_user, problem) %></p>
  </a>
</li>

关于mysql - 在 Rails 中将 3 个模型连接在一起以在迭代一个模型的 View 中显示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6810349/

相关文章:

php - MySQL,MySQLi和PDO有什么区别?

mysql - 为什么 select count(*) from table_name 这么慢?

ruby-on-rails - 如何找出 ruby 中每场比赛的起点

javascript - 如何在 Rails Turbolink 中正确使用 jQuery $().load(url)?

ruby-on-rails - Rails 无效的多字节字符 (US-ASCII) - Heroku 崩溃

ruby-on-rails-3 - 使用 RSpec 测试嵌套资源 Controller - 计数不会改变 1

php - Mysql从2个表循环数据

ruby-on-rails - 多态模型、Forms 和 AssociationTypeMismatch

ruby-on-rails-3 - Gemfile.lock 在 Rails 中使用?

mysql - 哪种数据库设计适合复杂的测验应用程序?