find_by_or_initialize_by*_and_* and increment!
I'm a little slow when it comes to programming, but I enjoy it and try to learn as much as I can. So apologies in advance if i'm not clear enough with my question.
I have an app with a sole purpose for DJs to review songs and the song reviews to be grouped by state. 5 Fields… songid, state, stdjlike, stthinkclublike, stplait (Horrible names I know, but they help me to remember what they are :)).
Once a user decides to review a song, they will be asked 3 questions which are answered on a scale of 1 to 5, the form collects the 3 answers as well as the users state and the id of the song. Most of the time the database will just find the state and song id, then add the new data to the 3 question fields (djlike, thinkclublike, plait). But the first review for a song from a user in a new state will have to create a new record.
So again, just to be crystal clear, the first time a user from "New York" reviews (song) "123" it will create a new record with the song id, state name, and add the review values to the 3 columns stdjlike, stthinkclublike and stplait. Next user, a different user, from NY for song "123" creates a review, it will just update the record, adding the values for stdjlike, stthinkclublike and stplait to the previous review.
I have been looking around all week and finding lots of good solutions to similar but not the same problems (A well documented solution here). I decided to go with increment because I'm updating with values that aren't fixed numbers, I've been trying but I just can't get it to work.
I started with what works. The create in the reviewstate controller saves the record when it is just a simple .new and .save. So i changed it from there to this..
def create
@reviewstate = Reviewstate.find_or_initialize_by_songid_and_state(song.id, current_user.state)
@reviewstate.stdjlike.increment!(:stdjlike, reviewstate.stdjlike)
@reviewstate.stthinkclublike.increment!(:stthinkclublike, reviewstate.stthinkclublike)
@reviewstate.stplait.increment!(:stplait, rev开发者_运维知识库iewstate.stplait)
@reviewstate.save!
end
Stops working. I have tried different variations and methods, this is when I feel the closest. Please help me, its been 4 days :).
Thank you in advance.
If find does not return a record and a new one is initialized, stdjlike will be nil (unless you set another default value in your migration). Thus, increment will try to increment by Nil. Nil is not a fixnum though and it will not work. I suppose that this is the error you get.
Moreover, you store your object in @reviewstate and then you refer to it by reviewstate.stdjlike. You have an instance variable @reviewstate and you then refer to the local variable reviewstate. They are two different objects.
You should handle things differently. Check if your record exists. If yes, just get it. If not, create it. Use Reviewstate.exists?.
Also, bear in mind that Ruby uses underscores as a convention for names. That would make it something like std_jlike or something like that. But you can always use what you feel more comfortable with.
This is going to sound pretty drastic, but I think will make things simpler for you in the long run. I'm going to recommend a pretty big refactor. It sounds like you have a few things which should be their own models:
- User (or DJ)
- State
- Song
- Review
I would structure the application so that your reviews belong to one state, one user, and one song:
#user.rb
class User << ActiveRecord::Base
has_many :reviews
end
#state.rb
class State << ActiveRecord::Base
has_many :reviews
end
#song.rb
class Song << ActiveRecord::Base
has_many :reviews
end
#review.rb
class Review << ActiveRecord::Base
belongs_to :user
belongs_to :state
belongs_to :song
end
Then when you want to gather some form of statistics for display you derive it from the review records. This will allow you to get stats across states, DJ's, or songs.
This is also a more RESTful implementation where more objects in your system are represented as resources that can be (C)reated, (R)ead, (U)pdated, and (D)estroyed. In general doing things in a RESTful manner will make your life much easier when working in rails.
精彩评论