What does "first" do in Ruby and Rails?
Solution 1
find_by_foo
returns a single object. where
returns a collection (relation). Obviously you can't do photo.photo_id
when photo
is a collection of Photo
objects (instead of a single Photo
).
first
returns the first object of a collection. So by calling first
on the collection returned by where
, you get a single Photo
object that you can work with.
Note that Foo.where(:id => bla).first
is the same as Foo.find(bla)
, so you can just use
PhotoAlbum.find( Photo.find(params[:photo_id]).photo_album_id )
instead of
PhotoAlbum.where(:id => Photo.where(:id => params[:photo_id]).first.photo_album_id).first
Solution 2
I don't have commenting ability, so I was not able to comment on the above post, but I should point out:
Foo.where(:id => X).first
is NOT the same as Foo.find(X)
. Foo.find(X)
will raise an exception if there's no record with id = X, while the other one will just return nil.
Comments
-
LondonGuy almost 2 years
I implemented a feature that lets users set default profile photos and photo-album cover photos.
I have the following tables in my database:
- User(s) - has one profile, has many PhotoAlbums
- Profile(s) - belongs to user
- PhotoAlbum(s) - belongs to user, has many photos
- Photo(s) - belongs to PhotoAlbum
The action for setting a default profile photo is:
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
That works fine.
Setting my default album photo was a little trickier:
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
This is the action that didn't work:
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
I got it working, and the undefined
photo_id method
error went away, but that was after changing these lines from:photo.photo_id = params[:photo_id] photo.save
to:
photo.first.photo_id = params[:photo_id] photo.first.save
I am not sure what is happening, and why that change made things work, and want to understand what is going on.