在Ruby和Rails中"首先"做了什么?

Lon*_*Guy 2 ruby rubygems ruby-on-rails ruby-on-rails-3 ruby-on-rails-3.1

我实现了一项功能,允许用户设置默认配置文件照片和相册封面照片.

我的数据库中有以下表格:

  • 用户 - 有一个个人资料,有很多PhotoAlbums
  • 个人资料 - 属于用户
  • PhotoAlbum(s) - 属于用户,有很多照片
  • 图片 - 属于PhotoAlbum

设置默认个人资料照片的操作是:

def set_default_profile_photo
  photo = Profile.find_by_user_id(current_user.id)
  photo.photo_id = params[:photo_id]
  photo.save
  redirect_to :back
  flash[:success] = "Default photo set!"
end
Run Code Online (Sandbox Code Playgroud)

这很好.

设置我的默认相册照片有点棘手:

def set_default_album_photo
  photo = PhotoAlbum.where(:id => Photo.where(:id => params[:photo_id]).first.photo_album_id)
  photo.first.photo_id = params[:photo_id]
  photo.first.save
  redirect_to :back
  flash[:success] = "Default album photo set!"
end
Run Code Online (Sandbox Code Playgroud)

这是不起作用的动作:

def set_default_album_photo
  photo = PhotoAlbum.where(:id => Photo.where(:id => params[:photo_id]).first.photo_album_id)
  photo.photo_id = params[:photo_id]
  photo.save
  redirect_to :back
  flash[:success] = "Default album photo set!"
end
Run Code Online (Sandbox Code Playgroud)

我得到了它的工作,并且未定义的photo_id method错误消失了,但那是在更改这些行之后:

photo.photo_id = params[:photo_id]
photo.save
Run Code Online (Sandbox Code Playgroud)

至:

photo.first.photo_id = params[:photo_id]
photo.first.save
Run Code Online (Sandbox Code Playgroud)

我不确定发生了什么,为什么这种改变使事情有效,并且想要了解发生了什么.

小智 7

我没有评论能力,所以我无法对上述帖子发表评论,但我应该指出:

Foo.where(:id => X).first是不一样的Foo.find(X).Foo.find(X)如果没有id = X的记录,则会引发异常,而另一个将返回nil.


sep*_*p2k 6

find_by_foo返回一个对象.where返回一个集合(关系).显然你不能做什么photo.photo_id时候photo是一个Photo对象的集合(而不是一个Photo).

first返回集合的第一个对象.因此,通过调用first返回的集合where,您将获得可以使用的单个Photo对象.

注意与之Foo.where(:id => bla).first相同Foo.find(bla),所以你可以使用

PhotoAlbum.find( Photo.find(params[:photo_id]).photo_album_id )
Run Code Online (Sandbox Code Playgroud)

代替

PhotoAlbum.where(:id => Photo.where(:id => params[:photo_id]).first.photo_album_id).first
Run Code Online (Sandbox Code Playgroud)