Rails中的复杂查询

时间:2009-08-28 14:38:18

标签: ruby-on-rails

Rails和ActiveRecord在处理我会考虑处理单个模型的极其简单的查询方面做得非常好。我现在有一种情况,我需要做一些稍微复杂的事情 - 但仍然是微不足道的 - 我不知道该怎么做。

我有一个User has_many :images。每个Image has_many :thumbnails

在我的/images索引页面上,我实际上想要为属于登录用户的每个图像显示缩略图。一个简单的查询,但因为这样做涉及多个表的条件,我不知道如何以真正的Rails方式处理它。我宁愿避免编写SQL并处理随之而来的麻烦。

我看到rails提供:joins选项,但这似乎是一个非常优雅的事后想法。这是满足这种要求的最佳方式还是有一种我没有找到的更好的方法?

感谢。

更新:我被告知有关命名的范围,并且不得不承认现在对他们有一些非常不恰当的感受。这些允许相当复杂的条件非常优雅地应用大量的语法糖。例如,我可以在我的Image模型上为给定用户拥有的图像创建一个命名范围,并使其成为动态:

class Image < ActiveRecord::Base
  named_scope :owned_by, 
              lambda { 
                |user_id| { 
                  :conditions => { :user_id => user_id } 
                } 
              }
end

我还可以在我的缩略图模型上应用命名范围来指定小缩略图:

class Thumbnail < ActiveRecord::Base
  named_scope :small, :conditions => { :name => 'Small' }
end

现在我可以把它们连在一起做一些非常强大的东西,它们可以很好地读取。在我的控制器中,我可以返回给定用户的所有图像:

@images = Image.owned_by( current_user )

在我看来,我想显示小缩略图,所以我们大力链接:

<% for image in @images %>
  <tr>
    <td><%= h( image.name ) %></td>
    <td><%= link_to( image_tag( image.thumbnails.small.first.binary.uri, :alt => h( image.name ), :title => h( image.description ) ), :action => :show, :id => image.id ) %></td>
  </tr>
<% end %>

查看image_tag。对于每个图像,它识别第一个小缩略图,然后将其链接以检索其物理文件位置。这并不是我想要的,因为它需要为每个图像额外的数据库命中,但它可能更准确地满足我在这个特定实例中的需求。

3 个答案:

答案 0 :(得分:3)

RailsGuides总是很方便,我花了很多时间在那里。

查看has_many:through assocation,它允许Images模型连接这些表并允许与Image相关的其他字段。

Thumbnail
has_many :images
has_many :users, :through => :images

Image
belongs_to :user
belongs_to :thumbnail

User
has_many :images
has_many :thumbnails, :through => :images

然后在访问与您可以执行的用户相关的缩略图时;

@user.thumbnails

或者缩略图应该有一个图像和一个用户?

Thumbnail
belongs_to :image

Image
belongs_to :user
has_one :thumbnail

User
has_many :images
has_many :thumbnails, :through => :images

Here's the example I gleaned this from.

答案 1 :(得分:2)

要精美地编写复杂查询,您还可以使用像松鼠这样的东西。 Squirrel是一个插件,允许您以更自然的方式编写复杂的查询:

User.find(:all) do
  first_name == "Jon"         # first_name = 'Jon'
  email =~ "%@thoughtbot.com" # email LIKE '%@thoughtbot.com'
  created_at >= 4.years.ago   # created_at >= '2004-06-27 10:34:22'
  awesomeness <=> (1..10)     # awesomeness BETWEEN 1 AND 10
  banned_since == nil         # banned_since IS NULL
end

您甚至可以使用关联(这是您需要的):

Post.find(:all) do
  user.first_name.contains? "Jon" 
end

Squirrel - Natural Looking Queries for Rails的更多信息。另外,请务必查看Github上的维基页面。

答案 2 :(得分:0)

对于特定用户,您可以通过执行此类操作找到所有缩略图

@user = User.find(:id, :include => :thumbnails)

:必须在用户模型中定义缩略图,因为他的答案中显示了像revgum这样的关联。