I am wondering how you add a value to an existing object versus
creating a new instance of the object. Specifically, I have a button
to klap (clap) for a photo like so:
<%= form_tag( :action => "klap") %>
<%= hidden_field :photo_id, :value => params[:photo_id] %>
<%= image_submit_tag("/images/clap.gif", {:alt => 'klap' }) %>
<%= end_form_tag() %>
Now I want to add one to the klap field for the specific photo_id each
time this button is clicked. Any idea how to do this? this is all i
have for my klap method in the controller right now:
def klap
redirect_to :back
end
I’m assuming i have to find the photo object first, so i was thinking
something along the lines of:
@photo = Photo.find(:all, :conditions => { :photo_id =>
params[:photo_id] })
is this the most efficient way to do this?
Then im assuming its something like @photo.klap.Add… Im just not
sure what the add function looks like. Thanks, Dave
Is the @photo = Photo.find(params[:photo_id]) less efficient? Does it
take longer? b/c otherwise i am getting this error: Unknown key(s):
value31.
Also, the .increment method doesnt seem to be working. i am getting
this error as well:
undefined method `increment’ for []:Array
any ideas, thanks.
On Mar 6, 2:28 am, Thorsten M. [email protected]
@photo = Photo.find(:all, :conditions => { :photo_id =>
params[:photo_id] })
is this the most efficient way to do this?
this is correct and would work, but for finding a single record just do:
@photo = Photo.find(params[:photo_id])
then
@photo.increment(:klap)
or
@photo.increment!(:klap)
the second variant would save the record
Is the @photo = Photo.find(params[:photo_id]) less efficient? Does it
take longer? b/c otherwise i am getting this error: Unknown key(s):
value31.
oops, didn’t read your code properly. you’re using a form_tag instead of
form_for which is not exactly rails like
I’m not sure, what you get returned in params[:photo_id] in that case
for the hidden field
Photo.find(params[:photo_id]) works only in the case, that
params[:photo_id] contains an (numeric?) id. seems yours contains
value31 instead of 31
Also, the .increment method doesnt seem to be working. i am getting
this error as well:
undefined method `increment’ for []:Array
that’s with your finder
Photo.find(:all,…) will return an array with all photos that match the
search
in that case use @photo[0].increment(:klap)
or use:
Photo.find(:first, :conditions => {:photo_id => params[:photo_id] })
that will return only one record as an object of expected type
Dave L. wrote:
This doesnt seem to be working either, says i get a nil object…
Do you know anything about the increment_counter method? this seems
to be what i need, but I cant get it working. the code i have is:
Photo.increment_counter(:klaps, params[:photo_id])
Im not sure if this is how I get the photo object?
On Mar 6, 3:18 am, Thorsten M. [email protected]
sorry, but you’re doing something very wrong here. if you have a nil
object after the find, it didn’t find what you expect and no function
will work
increment_counter differs from increment only by using some kind of
caching
increment:
increment_counter:
as far as i can see, your params[:photo_id] contains something, that
doesn’t match your database
you can check this easy enough:
have a look in log/development.log
in this file each call to an action is logged together with params.
there you can see, what is handed to your controller/action for
params[:photo_id]
This doesnt seem to be working either, says i get a nil object…
Do you know anything about the increment_counter method? this seems
to be what i need, but I cant get it working. the code i have is:
Photo.increment_counter(:klaps, params[:photo_id])
Im not sure if this is how I get the photo object?
On Mar 6, 3:18 am, Thorsten M. [email protected]
Dave L. wrote:
Im not sure if this is how I get the photo object?
It’s a little difficult without knowing the details of the method which
creates this form of yours, however I’ll try…
Get the method which generates this form (I’m calling it #show_form
here) to get the photo object in question. You seem to be setting the
parameter :photo_id so I’ll assume you have this somewhere in @photo_id,
say:
def show_form
:
@photo = Photo.find(@photo_id)
:
Then in your view:
<% form_for :photo, :url => { :action => :klap } do |f| %>
<%= image_submit_tag("/images/clap.gif", {:alt => ‘klap’ }) %>
<% end %>
Then back in the controller:
def klap
@photo = Photo.find(params[:id])
@photo.increment!(:klap)
render :action => :show_form
end
Liberally sprinkle with error checking. The use of “form_for” means you
get the id of the object preserved for free. This is very inefficient
use of the browser, of course, and an AJAX call would work much better.
Ok, this is helpful. First off, is there any way to purge all the
data in the development log. It is very big now. Second, here is the
snippet for my request:
Processing UsersController#klap (for 127.0.0.1 at 2008-03-06 03:42:45)
[POST]
Session ID: 906f107fa4549404292991c60e696aac
Parameters: {“x”=>“22”, “y”=>“19”, “action”=>“klap”,
“controller”=>“users”, “photo_id”=>{“value31”=>“”}}
[4;36;1mPhoto Load (0.001000) [0m [0;1mSELECT * FROM photos
WHERE (photos.id
= ‘— \n- value31\n- ""\n’)
Im not sure what is going wrong here but it doesnt look like any
object is being passed back.
On Mar 6, 3:33 am, Thorsten M. [email protected]
Dave L. wrote:
Ok, this is helpful. First off, is there any way to purge all the
data in the development log. It is very big now. Second, here is the
snippet for my request:
two ways:
- open in editor, select all, save
- rake log:clear
don’t delete the file, or you may get some trouble with permissions
Processing UsersController#klap (for 127.0.0.1 at 2008-03-06 03:42:45)
[POST]
Session ID: 906f107fa4549404292991c60e696aac
Parameters: {“x”=>“22”, “y”=>“19”, “action”=>“klap”,
“controller”=>“users”, “photo_id”=>{“value31”=>""}}
[4;36;1mPhoto Load (0.001000) [0m [0;1mSELECT * FROM photos
WHERE (photos.id
= ‘— \n- value31\n- “”\n’)
Im not sure what is going wrong here but it doesnt look like any
object is being passed back.
you get “photo_id”=>{“value31”=>""}} instead of “photo_id”=>“31”
can’t work. i think you must replace
<%= hidden_field :photo_id, :value => params[:photo_id] %>
with
<%= hidden_field_tag(:photo_id, params[:photo_id]) %>
if you use form_tag
Actually, one last question before i go to bed. how would i go about
making it so that a user that is signed in (checked by the user_id
in :session) can only do one klap per photo? Would I have to record
which photos a user has made a klap for in the appropriate user object
and then cross reference this to check if they have submitted a klap
or not? Im just wondering if there is any easy way to do this.
thanks for all your time, Dave
Awesome, that worked. thanks a lot, you really helped me out. one
last question, mark mentioned above that it is more efficient to use
form_for, is this true? also, i dont know much about ajax, but would
it be better to use form_for to ajax this request? Thanks again.
On Mar 6, 3:52 am, Thorsten M. [email protected]
Dave L. wrote:
mark mentioned above that it is more efficient to use
form_for, is this true?
Not more efficient. It’s just that if you have a specific object that
the form is “about” then using “form_for” usually makes everything
easier. Well, it does to me and obviously it’s a personal choice thing.
also, i dont know much about ajax, but would
it be better to use form_for to ajax this request?
Again, the way you code the form won’t make any difference to what
actually happens. Some situations lend themselves more to one way than
another.
For AJAX stuff you don’t even need a form. Helpers like
“remote_button_to” create their own form.
Although the AWDWR book is not so referenced here any more due to the
change in scaffolding, it has great introductions on how to create and
use forms and also for doing this sort of stuff using AJAX. I’d highly
recommend it.
Actually, one last question before i go to bed. how would i go about
making it so that a user that is signed in (checked by the user_id
in :session) can only do one klap per photo? Would I have to record
which photos a user has made a klap for in the appropriate user object
and then cross reference this to check if they have submitted a klap
or not? Im just wondering if there is any easy way to do this.
thanks for all your time, Dave
I’ve never had to code this myself and don’t know how sites that use
this stuff do it, but one solution would be to have an associated table
for user klaps with columns for user_id and photo_id such that each row
is unique (you could place a unique index on the table covering both
columns). If a user and photo are already in the table then don’t count
the klap. This would be a HABTM relationship between users and photos.
You can then see what photos a user has klapped (user.photos) and which
users have klapped a photo (photo.users). Then you can do something
like:
@photo.increment!(:klap) unless user.photos.include? @photo
Dave L. wrote:
Awesome, that worked. thanks a lot, you really helped me out. one
last question, mark mentioned above that it is more efficient to use
form_for, is this true? also, i dont know much about ajax, but would
it be better to use form_for to ajax this request? Thanks again.
yes, whenever you work with ActiveRecord Objects it’s much better to use
form_for, since lots of stuff is done by rails in the background,
ensuring, that paths and params work as expected
for ajax calls you would use remote_form_for
Actually, one last question before i go to bed. how would i go about
making it so that a user that is signed in (checked by the user_id
in :session) can only do one klap per photo? Would I have to record
which photos a user has made a klap for in the appropriate user object
and then cross reference this to check if they have submitted a klap
or not? Im just wondering if there is any easy way to do this.
thanks for all your time, Dave
you would need an intermediate table to store this relation between
users and photos, since for each combination of user/photo there must be
an entry
that would be an has_and_belongs_to_many association
quite some work for such a simple thing
ok, cool, that helps. so i have another database relationship
question. I have a user_id column in my photo_comments table and i
want to link it to my avatar table, which also has a user_id column.
I can’t use the belongs to method b/c it would look for an avatar_id
field. I want to display the avatar pictures next to the user’s
comments. This is what i have so far:
<% for comment in @comments -%>
on <%= comment.created_at.strftime(’%m-%d-%Y’) %> @ <%=
comment.created_at.strftime(’%I:%M’) %> <%= comment.user.screen_name
%> said:
br/><%= white_list comment.comment %>
<% end -%>
any suggestions are greatly appreciated.
hmmm, im getting an error that says:
ArgumentError in UsersController#test
Unknown key(s): through
this is my test method is UserController:
def test
@comments = PhotoComment.find(:all, :conditions => { :photo_id =>
params[:photo_id] })
end
class PhotoComment < ActiveRecord::Base
belongs_to :user
has_one :avatar, :through => :user
end
not sure what this means.
On Mar 6, 7:22 am, Thorsten M. [email protected]
ok, cool, that helps. so i have another database relationship
question. I have a user_id column in my photo_comments table and i
want to link it to my avatar table, which also has a user_id column.
I can’t use the belongs to method b/c it would look for an avatar_id
field. I want to display the avatar pictures next to the user’s
comments. This is what i have so far:
yes, you can use it
in photo_comments you must have something like
belongs_to :user
and in user:
has_one :avatar
you can add to photo_comments:
has_one :avatar, :through => :user
and access with
comment.avatar.image_file_name (or whatever column the filename is
stored in)
in the view something like:
<%= image_tag("/path/#{comment.avatar.image_file_name}") %>
should work
(if this doesn’t work, pls post some details about those three models,
the relevant associations and column names)
sweet, i removed the through and just left has_one :avatar in the
photoComment model and it worked perfectly. thanks so much.
On Mar 6, 7:43 am, Thorsten M. [email protected]
checked that, the :through exists only for belongs_to and has_many
but never mind, remove the has_one, you can just use
comment.user.avatar
should work as good as the other variation