Is there a difference between
def create
#user = User.new(params[:user])
if #user.save
redirect_to root_url, :notice => "Signed up!"
else
render :new
end
end
and
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to(:users, :notice => 'Registration successfull. Check your email for activation instructions.') }
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
Ignore the error and notice issues, my main question is the difference between using xml format and not using it, they seem to do the exact thing.
Using respond_to with different format than html give you the ability to have the response in the specified format (useful for web-service).
In that case (User creation) I don't think it is really useful, but it's all up to you!
Not using respond_to like your first exemple will simply render html.
More infos about respond_to here:
http://apidock.com/rails/ActionController/MimeResponds/InstanceMethods/respond_to
Related
I'm trying to get my head around saving to multiple models from the one controller and it's probably really simple but I can't figure it out.
I have a User Model that has many loanitems and the loanitems belong to the user associations set up.
In my loanitems controller I want each loanitem create action to update a the user.points
So at the moment I have the following code that doesn't throw any errors but doesn't update the user model either.
def create
#loanitem = current_user.loanitems.build(params[:loanitem])
respond_to do |format|
if #loanitem.save
#loanitem.user.points = #loanitem.user.points + 50
#loanitem.user.save
format.html {redirect_to root_path, :flash => {:success => "Loan Item created" } }
format.xml{render xml: root_path}
else
format.html {render 'pages/home' }
format.xml {render xml: 'pages/home'}
end
end
end
I'm also trying the following variation on a theme
def create
#loanitem = current_user.loanitems.build(params[:loanitem])
respond_to do |format|
if #loanitem.save
current_user.points = current_user.points + 50
current_user.save
format.html {redirect_to root_path, :flash => {:success => "Loan Item created" } }
format.xml{render xml: root_path}
else
format.html {render 'pages/home' }
format.xml {render xml: 'pages/home'}
end
end
end
But should I be sending some message instead to the userupdate controller instead? That currently looks like this ...
def update
#user = User.find(params[:id])
if
#user.update_attributes(params[:user])
redirect_to #user, :flash => { :success => "Profile has been updated!"}
else
#title = "Edit Profile"
render 'edit'
end
end
Or I have heard that the business logic really should all be contained in the model so maybe the method should be written in User.rb and then called by the Loanitems controllers create method?
I know it's a real rookie question but any advice would be really welcome.
It sounds like you need to use a Transaction, so you can modify multiple items as a single atomic unit:
def create
respond_to do |format|
User.transaction do
begin
#loanitem = current_user.loanitems.create!(params[:loanitem]) # raises exception if it can't create
#loanitem.user.update_attributes!(:points => #loanitem.user.points + 50) # raises exception if it can't update
format.html {redirect_to root_path, :flash => {:success => "Loan Item created" } }
format.xml{render xml: root_path}
rescue ActiveRecord::RecordInvalid
format.html {render 'pages/home' }
format.xml {render xml: 'pages/home'}
raise ActiveRecord::Rollback
end
end
end
end
This allows you to have a simple happy-path where multiple objects are updated/created and roll-back all changes so far if anything goes wrong and render your error handling logic. The objects will have the validation messages you can display to the user.
I have an option for a user to update their username in their profile. However, when the url for their profile has been set as localhost/user/username and when they submit their changes, they are redirected to their old username (not the new updated one).
Here is my update from users_controller.rb
Any suggestions?
def update
#user = User.find_by_username(params[:id])
#page_title = "Edit Profile"
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to(user_url,
:notice => "Your profile has been saved.") }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #user.errors,
:status => :unprocessable_entity }
end
end
end
also, I'm using
def to_param
username
end
Doesn't user_url take #user as an argument? How have you defined your route for that?
One thing I can think of immediately is #user.reload!.
I am still a bit new to RoR, and am using scaffolding to generate CRUD interfaces for data.
I am using devise for user authentication, and want to allow a user that owns a specific entry to edit or delete, but protect that data from other users. However, I would like to allow a different user to revise or create new versions.
So if a user that attempts to edit should appear as if they are editing, but when they submit, the controller should actually generate a new entry (and potentially specify the parent_id of the entry it derived from).
Any help on implementation is greatly appreciated.
Also look into Ancestry, it's a really nice library to help with versioning.
Here is my solution that I came up with. I am a ruby newb, so I assume that I can just call the create function with the same params but wasn't sure how to do that, so I just duplicated code:
def update
#section = Section.find(params[:id])
if #section.owner == current_user.id
respond_to do |format|
if #section.update_attributes(params[:section])
format.html { redirect_to(#section, :notice => 'Section was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #section.errors, :status => :unprocessable_entity }
end
end
else
# REVISE
#childsection = Section.new(params[:section])
respond_to do |format|
if #childsection.save
format.html { redirect_to(#childsection, :notice => 'Section was successfully revised.') }
format.xml { render :xml => #childsection, :status => :created, :location => #childsection }
else
format.html { render :action => "new" }
format.xml { render :xml => #childsection.errors, :status => :unprocessable_entity }
end
end
end
end
I'm diving into RoR and as I'm going through the tutorials, scaffolds, and docs, I'm coming across some code that confuses me. For example, I just read up on the 'redirect_to' method, but the guide I read didn't cover the example of redirecting to an instance var, such as the code that is generated in a typical scaffold...
# POST /articles
# POST /articles.xml
def create
#article = Article.new(params[:article])
respond_to do |format|
if #article.save
format.html { redirect_to(#article, :notice => 'Article was successfully created.') }
format.xml { render :xml => #article, :status => :created, :location => #article }
else
format.html { render :action => "new" }
format.xml { render :xml => #article.errors, :status => :unprocessable_entity }
end
end
end
In the statement format.html { redirect_to(#article, :notice => 'Article was successfully created.') }, the code is redirecting to the instance var article, which causes a 'redirect_to' the show method in the current controller. Why does this cause it to redirect to the show method?
Thanks so much for your help!
Why does this cause it to redirect to the show method?
Because if you don't specify particular action, Rails assumes you want to 'show' object. If you have another action in mind, try
redirect_to :action => :do_something, :id => #article
When I:
self.save
or
save!
in a model it automatically redirects me to the show view for that given model. How can I override this? I want to save the model and then go to another action/view in the same controller.
In particular, I have a process where I save a members details, and then I want to continue the process by going to the next page, e.g. payment page, that uses the id of the saved model.
In your controller you might have a block like:
def create
#user = User.new(params[:place])
respond_to do |format|
if #user.save
format.html { redirect_to(#user, :notice => 'User 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
You can change the target of the redirect_to (after format.html) from here - at present it is directing you to the record for that user, ie. #user. Take a look at http://api.rubyonrails.org/classes/ActionController/Base.html for a bit more info.
You likely have a block like this in your create/update methods:
respond_to do |format|
if #post.save
format.html { redirect_to(#post, :notice => 'Post was successfully created.') }
format.xml { render :xml => #post, :status => :created, :location => #post }
else
format.html { render :action => "new" }
format.xml { render :xml => #post.errors, :status => :unprocessable_entity }
end
end
So if your instance variable is named #post, and it's redirecting to the show view for the post after it saves, all you have to do is change the "redirect_to(#post, ..." part to whatever you want. Say you wanted to redirect to the root of your site - you could instead have
redirect_to(root_path, :notice => 'Post was successfully created.')
In your particular case, you could use something like this if you have your routes set up:
redirect_to(payment_page_path(#post), :notice => 'Post was successfully created.')
Hope that helps!
if you call save from your Model you will not be directed anywhere, it just does a direct model access save to the database. Your redirections are described in your controller in your create and update actions. you can find a list of routes by running rake routes and then pick the path you want your app to render when you save your model instance. you may have a route called payment_path which might look like this in your controller
map.payment :controller => :payments_controller, :action => index
and you would say in your create action
def create
if #item.save(params[:item])
redirect_to payment_path
else
flash[:error] = "there was a problem"
render :action => buy
end
end
if you need to pass a param, like user id to your route, then you need to include that in the path parameters
redirect_to payment_path(#user) #=> automagically finds the id of active record models