Accepts_nested_attributes_for child validation not working - ruby-on-rails-3

I have a model called Test that accepts_nested_attributes_for SubTest. A Test basically has an id, and there are multiple SubTests associated with an individual Test.
I want to validate that an attribute of the SubTest is numeric. Here are my models so far.
class Test < ActiveRecord::Base
has_many :sub_tests
accepts_nested_attributes_for :sub_tests
end
class SubTest < ActiveRecord::Base
belongs_to :test
validates :measurement, :numericality => true, :allow_nil => true
end
Here is the Test controller
def create
respond_to do |format|
if #test.save
flash.now[:notice] = "Test Created"
format.html { redirect_to(#test) }
format.xml { render :xml => #test, :status => :created, :location => #test }
format.js
else
flash.now[:error] = "[Error] Test Not Created Because: #{#test.errors.full_messages.join(", ")}"
format.html { render :action => "new" }
format.xml { render :xml => #test.errors, :status => :unprocessable_entity }
format.js
end
end
end
I want the create action in the controller to throw an error if the user enters a non-numeric string in the form for the sub_test.
Currently, if I enter non-numeric values for a sub_test.measurement, Rails doesn't create the Test or SubTest objects (desired behavior). But for some reason no error is thrown, and the Test controller triggers the create.js.erb partial.
I'm getting the impression that the validation for the numericality of sub_test.measurement should actually happen in the Test model, but I'm not sure how to write a custom validation method that tests for numericality.
Thanks in advance!

Got it. I needed to specify an _error.js.erb partial in my Test controller.
def create
respond_to do |format|
if #test.save
flash.now[:notice] = "Test Created"
format.html { redirect_to(#test) }
format.xml { render :xml => #test, :status => :created, :location => #test }
format.js
else
flash.now[:error] = "[Error] Test Not Created Because: #{#test.errors.full_messages.join(", ")}"
format.html { render :action => "new" }
format.xml { render :xml => #test.errors, :status => :unprocessable_entity }
format.js { render :partial => 'error' }
end
end
In the error partial I just appended my #messages div (since I'm doing form submissions through ajax.)

Related

respond_with and how to set redirect location?

I have the following that update user profile. It does perfectly fine with base url (http://domain_name.com/users/).
def update
#user = User.find(params[:id])
respond_with #user do |format|
if #user.update_attributes(params[:user])
if current_user.becomes(User) == #user
sign_in(#user, :bypass => true)
end
flash[:notice] = 'User was successfully updated.'
format.html { redirect_to #user }
format.json { render :status => :ok }
else
format.html { render :action => 'edit' }
format.json { render :status => :bad_request }
end
end
end
Now I want to move it into admin namespace (http://domain_name.com/admin/users/). And what I try is to change
redirect_to #user
to
redirect_to admin_user_path(#user)
then I got:
def update
#user = User.find(params[:id])
#respond_with(#user) do |format|
respond_with(#user, :location => admin_user_path(#user)) do |format|
if #user.update_attributes(params[:user])
if current_user.becomes(User) == #user
sign_in(#user, :bypass => true)
end
flash[:notice] = 'User was successfully updated.'
format.html { redirect_to admin_user_path(#user) }
format.json { render :status => :ok }
else
format.html { render :action => 'edit', :location => edit_admin_path(user) }
format.json { render :status => :bad_request }
end
end
end
But it does not work. I also try to change
respond_with(#user) do |format|
to something like
respond_with(#user, :location => admin_user_path(#user)) do |format|
But it doesn't work too. Can anyone have some experience, please give me some advice or explanation.
Thanks!
I do believe the following line:
respond_with(#user, :location => admin_user_path(#user)) do |format|
Seems a bit odd to me. I would've thought this should be respond_with(#user) do |format|
Also take a read of the following: Ryan's Scraps - Cleaner RESTful Controllers / respond_with. Ryan states the following under Pre-Action Overriding:
It’s also possible to override standard resource handling by passing in a block to respond_with specifying which formats to override for that action.
From this you will see that the formats that are to be overrided are declared at the top of the class using respond_to

undefined method for nil:NilClass

upload controller
def create
#upload = #order.uploads.build(params[:uploadtwo])
respond_to do |format|
if #upload.save
format.html { redirect_to root_path, :notice => 'File was successfully uploaded.' }
format.json { render :json => #upload, :status => :created, :location => #upload }
else
format.html { render :action => "new" }
format.json { render :json => #upload.errors, :status => :unprocessable_entity }
end
end
upload model
belongs_to :order
order model
has_many :uploads
i get error [NoMethodError in UploadtwosController#create ], [undefined method `uploads' for nil:NilClass]
anybody knows what am not doing?
Just declaring belongs_to :order in your Upload model does not mean that #order will automatically be defined in the controller. Perhaps what you want is a before_filter in the controller which will set #order?

rails redirect or render with a specific verb

I want to redirect to a resource index when a new item is created
Here is a piece of the controller:
def create
#asset = Asset.new(params[:asset])
#assets = Asset.all
respond_to do |format|
if #asset.save
format.html { render :action => 'index' } ##########
format.xml { render :xml => #asset, :status => :created, :location => #asset }
else
format.html { render :action => "new" }
format.xml { render :xml => #asset.errors, :status => :unprocessable_entity }
end
end
end
The line i'm interested is marked ##########
i've tried
format.html { redirect_to(assets_url) }
and some other stuff
It redirects to the right place and creates the item fine, the problem is that i cant get it to not POST. I need to get it to GET because otherwise it does some horribly screwy things to my view.
redirect_to :action => :index Or redirect_to assets_url should work for you. Also, index action is always GET request. Do rake routes to see what kind of request happens for each action in your controller.

Include two database results in one API request output using Rails 3

I am developing an API in Rails 3 and I got a user model and a message model.
I want the developer to be able to get all info about the user as well as the last message from the user. How can I do this? How can I "include" the messages into the user output?
How can this code be modified to suit my purpose?
def index
#contacts = current_user.contacts
#users = Array.new
#messages = Array.new
#contacts.each do |contact|
user = User.find(contact.friend_id)
#users << user
message = Message.find_by_user_id(contact.friend_id)
#messages << message
end
respond_to do |format|
format.html { render :text => 'Use either JSON or XML' }
format.json { render :json => #users }
format.xml { render :xml => #users }
end
end
Thankful for all input!
You should take advantage of your model, and include the last message as a method in your User model. You can then use the :methods hash of the render method.
format.json { render :json => #users , :methods => [:last_message]}
EDIT
Your user model should be something like:
def User < ActiveRecord::Base
has_many :messages
attr_accessor :name, :email #Include the fields you wish to show here
def last_message
self.messages.first
end
end
And your controller:
def index
#contacts = current_user.contacts
respond_to do |format|
format.html { render :text => 'Use either JSON or XML' }
format.json { render :json => #contacts, :methods => :last_message }
format.xml { render :xml => #contacts, :methods => :last_message }
end
end

failed to test create action

I am playing with rails 3.0.6 with ruby 1.9.2,
the app is working on browser but not in testing..
1) I created a new rails application by "rails new myapp"
2) Generate a scaffold "rails generate scaffold user username:string hashed_password:string salt:string"
3) after that, i changed the users_controller a bit
# POST /users
# POST /users.xml
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
// change #user to usrs_url
format.html { redirect_to(users_url, :notice => "User #{#user.username} was successfully created.") }
format.xml { render :xml => #user, :status => :created, :location => #user }
else
format.html { render :action => "new" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
# PUT /users/1
# PUT /users/1.xml
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
// change #user to usrs_url
format.html { redirect_to(users_url, :notice => "User #{#user.username} was successfully updated.") }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
4) so i try to modify tests as well:
setup do
#input_attributes = {
:username => 'username#goodmail.com',
:password => 'secret',
:password_confirmation => 'secret'
}
#user = users(:one)
end
test "should create user" do
assert_difference('User.count') do
post :create, :user => #input_attributes
end
assert_redirected_to users_path
end
test "should update user" do
put :update, :id => #user.to_param, :user => #input_attributes
assert_redirected_to users_path
end
But the create and update tests failed
Can anyone let me know what had i done wrong?
Thanks
Loaded suite C:/Ruby192/lib/ruby/1.9.1/rake/rake_test_loader
Started
F.....F
Finished in 5.628874 seconds.
1) Failure:
test_should_create_user(UsersControllerTest) [test/functional/users_controller_test.rb:26]:
"User.count" didn't change by 1.
<3> expected but was
<2>.
2) Failure:
test_should_update_user(UsersControllerTest) [test/functional/users_controller_test.rb:45]:
Expected block to return true value.
7 tests, 9 assertions, 2 failures, 0 errors, 0 skips
require 'digest/sha2'
class User < ActiveRecord::Base
validates :username, :presence => true, :uniqueness => true
validates_format_of :username, :with => /\A^[^\r\n# ][^\r\n# ]+#[^\r\n# ]+[.][^\r\n#. ]+$\Z/i
#password is a fake field
validates :password, :confirmation => true
validate :password_must_be_present
attr_accessor :password_confirmation
attr_reader :password
def password=(password)
if password.present?
generate_salt
self.hashed_password = self.class.encrypt_password(password, salt)
end
end
class << self
def encrypt_password(password, salt)
Digest::SHA2.hexdigest(password + "shrimpy" + salt)
end
def authenticate(username, password)
if user = find_by_username(username)
if user.hashed_password == encrypt_password(password, user.salt)
user
end
end
end
end
private
def password_must_be_present
errors.add(:password, "Missing password") unless hashed_password.present?
end
def generate_salt
self.salt = self.object_id.to_s + rand.to_s
end
end
assert_redirected_to user_path is singular. You probably don't even have a singular user resource route defined. What you want there is probably assert_redirected_to users_path with a plural users.