Rails: update_column works, but not update_attributes - ruby-on-rails-3

I have a simple model:
class Reply < ActiveRecord::Base
attr_accessible :body
belongs_to :post
end
In my controller, I have a simple update method:
def update
#reply = Reply.find(params[:id])
if #reply.update_attributes!(params[:reply])
render :js => "alert('I am trying to update!')"
else
render :js => "alert('<%= #reply.errors %>')"
end
end
This doesn't throw an error, but neither does it actually update the reply. Instead, I get the "I am trying to update!" message, like everything worked. But when I reload the page and look at the reply, it has the same text. It hasn't actually been updated. If I replace update_attributes with:
#reply.update_column(:body, params[:reply][:body])
It works fine. If I use:
#reply.update_attribute(:body, params[:reply][:body])
It once again doesn't work. Any idea what's going?
In my log, I have this:
Started PUT "/posts/2/replies/20" for 127.0.0.1 at 2013-01-19 10:39:57 -0600
Processing by RepliesController#update as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Xot7E+ldXiBm0hVvw5XUP/U5guJU2g8e4QaLbDVGzDE=", "reply"=>{"body"=>"Updated text."}, "commit"=>"Submit Revision", "post_id"=>"2", "id"=>"20"
[1m[35mUser Load (1.0ms)[0m SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
[1m[36mReply Load (0.0ms)[0m [1mSELECT `replies`.* FROM `replies` WHERE `replies`.`id` = 20 LIMIT 1[0m
[1m[35m (1.0ms)[0m BEGIN
[1m[36mPost Load (0.0ms)[0m [1mSELECT `posts`.* FROM `posts` WHERE `posts`.`id` = 2 LIMIT 1[0m
[1m[35m (0.0ms)[0m COMMIT
Rendered replies/_reply_content.html.erb (502.0ms)
Rendered replies/update.js.erb (505.0ms)
Completed 200 OK in 849ms (Views: 484.0ms | ActiveRecord: 94.0ms)

The three methods you are using do different things:
update_attributes tries to validate the record, calls callbacks and saves;
update_attribute doesn't validate the record, calls callbacks and saves;
update_column doesn't validate the record, doesn't call callbacks, doesn't call save method, though it does update record in the database.
If the only method that "works" is update_column my guess is that you have a callback somewhere that is throwing an error. Try to check your log/development.log file to see what's going on.
You can also use update_attributes!. This variant will throw an error, so it may give you information on why your model isn't saving.
You should use update_attributes and avoid the two other methods unless you know exactly what you are doing. If you add validations and callbacks later to your model, using update_attribute and update_column can lead to nasty behaviour that is really difficult to debug.
You can check this link for more info on that.

I had this same issue, but with Rails 4. The issue happens when you have params[] in update_attribute. In Rails 4 with strong parameters
#reply.update_attributes(params[reply_params])
should be
#reply.update_attributes(reply_params)
I'm not to familiar with Rails 3 but this should be the issue:
#reply.update_attributes(params[:reply])
should be
#reply.update_attributes(:reply)

A gut guess would be to say that you have a mass assignment problem and should add your attributes in your model like this
attr_accessible: :your_attribute, :your_attribute2

Related

How can I re-build nested attributes fields on form validation errors in Rails 3

I have a simple form for Recommendations. REcommendations has_many Assets.
so in my controller I am doing a simple:
6.times {#recommendation.assets.build}
My issue occurs when I try to save the Recommendation and there are Validation errors. My Create action:
def create
#recommendation = Recommendation.new(params[:recommendation])
#recommendation.user_id = current_user.id
respond_to do |format|
if #recommendation.save
format.html { redirect_to thankyou_path, notice: 'Recommendation was successfully created.' }
else
6.times {#recommendation.assets.build} if #recommendation.assets.blank?
render action: "new"
end
end
end
running this page and submitting (with validation errors) causes the following log output and a http 406 error
Started POST "/categories/1/awards/9/recommendations" for 127.0.0.1 at 2013-01-07 11:50:13 -0800
Processing by RecommendationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"8PVfFZGa72+3KU/km2weZhNy0rxRfp0Qd+CkHdBoQM8=", "recommendation"=>{"nominee"=>"", "title"=>"", "department"=>"", "award_id"=>"9", "summary"=>"", "accomplishments"=>"", "caption"=>"", "url"=>"", "supervisor"=>"You ARE NOT the nominee’s direct manager / supervisor", "approvals_attributes"=>{"0"=>{"email"=>""}}}, "commit"=>"Save/Submit", "category_id"=>"1", "award_id"=>"9"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 2 LIMIT 1
(0.2ms) BEGIN
(0.1ms) ROLLBACK
Rendered shared/_recommend_timeline.html.erb (1.2ms)
Award Load (20.1ms) SELECT "awards".* FROM "awards" WHERE "awards"."id" = 9 LIMIT 1
Rendered recommendations/_form.html.erb (66.7ms)
Rendered recommendations/new.html.erb within layouts/application (69.8ms)
(0.5ms) SELECT COUNT(*) FROM "recommendations" WHERE "recommendations"."user_id" = 2
(0.6ms) SELECT COUNT(*) FROM "approvals" WHERE "approvals"."email" = 'tj#ravennainteractive.com' AND "approvals"."approved" IS NULL
Completed 406 Not Acceptable in 556ms (Views: 188.6ms | ActiveRecord: 31.5ms)
I have looked at multiple questions on stack that seem similar but
I'm not sure there is enough information to be able to answer with much confidence, but I don't think you want to rebuild exactly 6 times. Depending on your model setup, the validation could nullify one, but not all of the associations.
Perhaps you should try:
(6-#recommendation.assets.count).times {#recommendation.assets.build}
My guess is that your view is expecting exactly 6 assets but only finding somewhere from 1-5 after the invalid ones were thrown out, and that this is causing an internal error.
If that doesn't fix it, I think you may need to provide more information about what validations are running on assets, and what your view looks like.

Rails: controller method reading wrong model

I've got two models (Articles and Documents) and I'm working with them from a third controller (called Share). I've written this method in that controller to track clicks on articles and the like:
def read_more(a)
#article = Article.find(a)
impressionist(#article)
end
And for some bizarre reason my app tries to find a Document with an ID of, say, 17, instead of an Article. I'm completely stumped.
Any ideas? Cheers!
EDIT:
The log readout is:
Started GET "/share/read_more/17" for 127.0.0.1 at 2012-12-17 09:37:49 +1100
Processing by ShareController#show as JS
Parameters: {"ftp"=>"read_more", "id"=>"17"}
Document Load (0.1ms) SELECT "documents".* FROM "documents" WHERE "documents"."id" = ? LIMIT 1 [["id", "17"]]
Completed 500 Internal Server Error in 1ms
ActiveRecord::RecordNotFound (Couldn't find Document with id=17):
I figured out the answer, should anyone else come into a similar issue.
def read_more
#article = Article.find(params[:id])
impressionist(#article)
render :json => "Read."
end
Apparently you can't have arguments in controller methods.

Rails 3 using devise and best_in_place gem, will not update subscriber model

I have a rails 3 application using devise with the subscribers model. I would like the subscribers to update their account information in place using best_in_place gem, but I can't seem to get it to update the database. It will update on the screen, but not the database.
The error sees to suggest the subscriber existing is a bad thing, but it isn't since it would be impossible to update that subscriber if it didn't exist.
All I want to do is be able to allow the users to update their information in place from a the subscriber/accounts#show page that shows them their details.
my subscriber/accounts controller has this:
def update
#subscriber = Subscriber.find(current_subscriber.id)
#subscriber.update_without_password(params[:subscriber])
end
I always get these results in the server log:
Processing by Subscribers::AccountsController#update as JSON
Parameters: {"subscriber"=>{"firstname"=>"Aarof"}, "authenticity_token"=>"Sx6kEQy4NC56ovikMs/D9nVPGJt1q5jNCoFnNjFhDu8=", "id"=>"2"}
Subscriber Load (1.9ms) SELECT `subscribers`.* FROM `subscribers` WHERE `subscribers`.`id` = 2 LIMIT 1
CACHE (0.0ms) SELECT `subscribers`.* FROM `subscribers` WHERE `subscribers`.`id` = 2 LIMIT 1
(0.2ms) BEGIN
Subscriber Exists (0.4ms) SELECT 1 AS one FROM `subscribers` WHERE (`subscribers`.`email` = BINARY 'frostsquid#yahoo.com' AND `subscribers`.`id` != 2) LIMIT 1
(0.1ms) ROLLBACK
Redirected to http://localhost:3000/subscribers/accounts/2
Completed 302 Found in 12ms (ActiveRecord: 2.6ms)
my show page looks like this:
%p.subscriber-account-info
=best_in_place #subscriber, :firstname, :path => subscribers_account_path(#subscriber)
My routes for subscribers looks like:
subscribers_accounts GET /subscribers/accounts(.:format) subscribers/accounts#index
POST /subscribers/accounts(.:format) subscribers/accounts#create
new_subscribers_account GET /subscribers/accounts/new(.:format) subscribers/accounts#new
edit_subscribers_account GET /subscribers/accounts/:id/edit(.:format) subscribers/accounts#edit
subscribers_account GET /subscribers/accounts/:id(.:format) subscribers/accounts#show
PUT /subscribers/accounts/:id(.:format) subscribers/accounts#update
I just checked trying to update subscribers firstname using the console and received the same message that the subscriber exists and it rolled the transaction back. Is this because of something in Devise?
Maybe a little the answer, but do you respond to JSON? here sample code from our project:
def update
respond_to do |format|
resource_files_service.update(#resource_file, params[:resource_file], current_user)
format.html { }
format.json { respond_with_bip(#resource_file) }
end

Rails 3.1 custom controller action keeps asking for ID even when route is specified

I'm trying to add a custom action ('last_five') to a controller.
My routes are specified as:
people_last_five GET /people/last_five(.:format) {:action=>"last_five", :controller=>"people"}
(i.e. that's the output of rake_routes).
But when I browse to /people/last_five I get the following error.
Started GET "/people/last_five" for XXX.XX.XXX.XXX at Sun May 15 22:03:18 +0000 2011
Processing by PeopleController#last_five as HTML
User Load (1.4ms)^[[0m SELECT users.* FROM users WHERE users.id = 3 LIMIT 1
Completed in 86ms
ActiveRecord::RecordNotFound (Couldn't find Person without an ID):
I thought this was a problem in my routes.rb
In my routes.rb I currently have:
get 'people/last_five'
resources :people
I've also tried
resources :people do
get 'last_five', :on => collection
end
but that gives the same results.
Why is rails trying to get an ID when there is no "/:id/" in the route?
This even happens when I specify the route as '/people/:id/last_five' and pass it a dummy id. In that case it still tells me ActiveRecord::RecordNotFound (Couldn't find Person without an ID).
I have this problem even when I reduce the action itself to a stub for debugging, so I don't think that's the problem. In my controller:
# GET /people/last_five
def last_five
logger.info "LAST FIVE IS BEING CALLED"
##people = Person.last_five
#respond_with #people do |format|
# format.json { render :json => #people }
#end
end
Any idea what's going on here? It seems like rails is being told to get an ID by something outside of routes.rb. I've looked everywhere I can think.
Any leads are HIGHLY appreciated.
Thanks.
EDIT:
My PeopleController begins like so:
before_filter :authenticate_user!, :except => []
filter_resource_access
respond_to :html, :js, :json
Per the discussion on your questions, the cause is a before/around filter interfering rather than an issue with your specific action. Your application is searching for a User, so it may be authentication-related.
Are you sure this goes in Control, and not in Model? Rails doesn't want Model stuff in Control.

rails3-amf - to_amf method not found on ActiveRecord objects

I am using the rails3-amf gem by warhammerkid in my Rails 3 / Flex 4 project.
AFAIK, I have correctly followed the "Getting Started" instructions from the GitHub page.
I have added the gem lines to my Gemfile.
I have installed the gems using bundle install.
From my Flex application, I will be making the RemoteObject call to the index action in the ManageMySchool::GradesController file. This is the code in the app/controllers/manage_my_school/grades_controller.rb file:
class ManageMySchool::GradesController < ApplicationController
respond_to :html, :amf
def index
#grade = Grade.first
respond_with(#grade) do |format|
format.amf { render :amf => #grade.to_amf }
end
end
end
The name of the model which is to be serialized is called Grade in both the Rails project (app/models/Grade.rb) and the Flex project (Grade.as with a RemoteAlias set as Grade). In the config/application.rb file, I have done the class mapping this way:
config.rails3amf.class_mapping do |m|
m.map :as => 'Grade', :ruby => 'Grade'
end
And I have done a parameter mapping this way:
config.rails3amf.map_params :controller => 'ManageMySchool::GradesController', :action => 'index', :params => [:authenticity_token]
Problem
Now, when I run the server and make the RemoteObject call from Flex, I get a to_amf undefined method error for the Grade model.
If I change Grade.first to Grade.all, #grade would have an array of Grades. But the undefined method error message still mentions the Grade model. This means that the to_amf method is working for the Array class but not for the ActiveRecord model.
Why is this? What am I doing wrong?
Is there something I have to do to "enable" the rails3-amf gem for ActiveRecord models?
I would appreciate any insights. Thanks!
Update
#warhammerkid: Here is the output of Grade.ancestors as seen in rails console.
ree-1.8.7-2011.03 :006 > puts Grade.ancestors
Grade
ActiveRecord::Base
Paperclip::CallbackCompatability::Rails3::Running
Paperclip::CallbackCompatability::Rails3
Paperclip::Glue CanCan::ModelAdditions
Authlogic::ActsAsAuthentic::ValidationsScope
Authlogic::ActsAsAuthentic::SingleAccessToken
Authlogic::ActsAsAuthentic::SessionMaintenance
Authlogic::ActsAsAuthentic::RestfulAuthentication::InstanceMethods
Authlogic::ActsAsAuthentic::RestfulAuthentication
Authlogic::ActsAsAuthentic::PersistenceToken
Authlogic::ActsAsAuthentic::PerishableToken
Authlogic::ActsAsAuthentic::Password
Authlogic::ActsAsAuthentic::MagicColumns
Authlogic::ActsAsAuthentic::Login
Authlogic::ActsAsAuthentic::LoggedInStatus
Authlogic::ActsAsAuthentic::Email
Authlogic::ActsAsAuthentic::Base
ActiveRecord::Aggregations
ActiveRecord::Transactions
ActiveRecord::Reflection
ActiveRecord::Serialization
ActiveModel::Serializers::Xml
ActiveModel::Serializers::JSON
ActiveModel::Serialization
ActiveRecord::AutosaveAssociation
ActiveRecord::NestedAttributes
ActiveRecord::Associations
ActiveRecord::AssociationPreload
ActiveRecord::NamedScope
ActiveModel::Validations::Callbacks
ActiveRecord::Callbacks
ActiveModel::Observing
ActiveRecord::Timestamp
ActiveModel::MassAssignmentSecurity
ActiveRecord::AttributeMethods::Dirty
ActiveModel::Dirty
ActiveRecord::AttributeMethods::TimeZoneConversion
ActiveRecord::AttributeMethods::PrimaryKey
ActiveRecord::AttributeMethods::Read
ActiveRecord::AttributeMethods::Write
ActiveRecord::AttributeMethods::BeforeTypeCast
#<Module:0x1028356f0> ActiveRecord::AttributeMethods::Query
ActiveRecord::AttributeMethods
ActiveModel::AttributeMethods
ActiveRecord::Locking::Optimistic
ActiveRecord::Locking::Pessimistic
ActiveRecord::Validations
ActiveModel::Validations::HelperMethods
ActiveModel::Validations
ActiveSupport::Callbacks
ActiveModel::Conversion
ActiveRecord::Persistence Object
PP::ObjectMixin Base64::Deprecated
Base64
ActiveSupport::Dependencies::Loadable
Kernel
Note that only ActiveModel::Serialization is there. No mention of Rails3AMF.
Does this mean I have to do something special to load the Rails3AMF module for the ActiveRecord models?
I am using Rails 3.0.5 with the latest version of ree. The gems are all contained in a gemset managed using rvm.
Update 2
If I remove the to_amf in the render :amf line, then I get the following error:
Grade Load (0.3ms) SELECT `grades`.* FROM `grades` LIMIT 1
Completed 200 OK in 195ms (Views: 0.1ms | ActiveRecord: 0.8ms)
Sending back AMF
NoMethodError (You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.last):
Rendered /Users/anjan/.rvm/gems/ree-1.8.7-2011.03#rb/gems/actionpack-3.0.5/lib/> > action_dispatch/middleware/templates/rescues/_trace.erb (1.1ms)
Rendered /Users/anjan/.rvm/gems/ree-1.8.7-2011.03#rb/gems/actionpack-3.0.5/lib/> > action_dispatch/middleware/templates/rescues/_request_and_response.erb (2.8ms)
Rendered /Users/anjan/.rvm/gems/ree-1.8.7-2011.03#rb/gems/actionpack-3.0.5/lib/> > action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (13.6ms)
Started POST "/amf" for 127.0.0.1 at Fri Apr 15 17:03:34 +0530 2011
Sending back AMF
Update 3
If I manually add the line include Rails3AMF::Serialization at the top of the Grade.rb model file, then it all works. So, does this mean that I have to put this line in all my models?
I see that this is already being done in line numbers 40 - 42 in the lib/rails3-amf/serialization.rb file of the gem:
# Hook into any object that includes ActiveModel::Serialization
module ActiveModel::Serialization
include Rails3AMF::Serialization
end
Why isn't this working? Should I force-load the gem when my application initializes or something?
Thanks!
Update 4 - Solved by this workaround
Okay, I just ended up adding this code block in an initializer:
class ActiveRecord::Base
include Rails3AMF::Serialization
end
And it is working.
#warhammerkid - Thanks for the help.
Rails3AMF::Serialization, the module that adds the to_amf method, is included in ActiveModel::Serialization when Rails3-AMF loads. If it's somehow not being included even though the code is running and ActiveModel::Serialization is one of your model's ancestors, then the simplest solution is just to add "include Rails3AMF::Serialization" at the top of your model implementation. I've never tried gem sets before, but it might be an issue with them, as everything works correctly using Bundler.
As an aside, feel free to post a bug to https://github.com/warhammerkid/rails3-amf/issues.