Sticky Forms in Ruby on Rails - ruby-on-rails

How can I make a sticky form in rails?
Thanks

Rails scaffolds do this automatically, right? Your form behavior shouldn't be departing much from theirs.
When you do <% form_for #user %>, all of the user's attributes are automatically filled in to that form. When your user fails to validate and does not save, the form is displayed, and #user still has all of the attributes that the user originally submitted; therefore, the form fields fill themselves out as intended.

If upon submission it does not pass validation you want to send the user back to the same action without resetting it. To achieve this you need the following code in your controller:
render :action => 'new'
or
render :action => 'edit'
These 2 would typically be in the create and update method respectively.

Related

When is the object creation invoked in Ruby on rails?

class UserSessionsController < ApplicationController
def new
#user_session = UserSession.new
end
def create
#user_session = UserSession.new(params[:user_session])
if #user_session.save
flash[:notice] = "Successfully logged in."
redirect_to root_path
else
render :action => 'new'
end
end
Am new to RoR, So long i have been working on tradition c/c++ so i have some basic doubts about object creation and stuff,
In UserSessionsController there is two methods namely "new" and "create". In the "new" method an object for UserSession is created without any parameters and in "create" method again object is created with some parameter.
Initially i thought that the "new" method is redundant and removed it. But i recieved the following error
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
The code works fine if i include the "new" method. I couldn't see this method being called anywhere in the entire code. Am referring to following sample project
railscasts/160-authlogic
Kindly let me know how this object creation is happening.
Thanks.
new and create are part of CRUD.
new action is used to render the new view for the UserSessionsController. In new action you simply create an instance of UserSession model class with #user_session = UserSession.new. After this, new.html.***(* is template handler like erb, haml, etc) is rendered where you will enter details of UserSession object that you would like to be created. Upon submission of this form create action would be invoked.
In create action you collect the parameters passed from the new view with #user_session = UserSession.new(params[:user_session]) and when you say #user_session.save it actually creates a record in database table user_sessions
UPDATE
The new action is invoked when you click on the Login Link. Why is it invoked? Because you have defined the login_path in routes.rb
Since you are a beginner I would highly recommend you to:
Read the Getting Started with Rails which will help you to understand the fundamentals of a Rails Application development.
Then, I also recommend you to complete Learn Rails by Example By
Michael Hartl.
And finally, watch the Ruby on Rails Railscasts By Ryan Bates.
Although, you can search on Google and you will find many great resources for the Rails beginners but the above 3 are THE de facto ones.
The 'new' action is generally used in combination with a user interface that will accept input from the user such as a form. It is not strictly necessary that the new action create a new UserSession object, but it is necessary if you want to use a "form_for" helper.
<% form_for #user_session do |f| %>
As you can see, if #article is not defined, this form will raise an error. The benefits of using form_for are that rails will automatically generated the correct params for you when you submit the form and send the form-data to the create action. For example:
<% form_for #user_session do |f| %>
<%= f.label :user_session %><br />
<%= f.text_field :user_session %>
<p><%= f.submit "Submit" %></p>
<% end %>
This form will create a param user_session[:user_session] when you submit the form. Now, when you call:
#user_session=UserSession.new(params[:user_session])
the #user_session object will have its user_session attribute automatically set to the value passed in by the form. This might seem trivial when there is only one attribute, but in a form with many attributes the ability to instantiated a new object and set all the attributes in one line is nice.
This functionality can be recreated by hand but the form_for helper does all the work for you.
In UserSessionsController the new and create methods refer to controller actions that correspond to particular RESTful HTTP requests (routes). In this case, a GET /user_sessions/new HTTP request would invoke UserSessionsController#new and a POST /user_sessions HTTP request would invoke UserSessionsController#create.
The new action renders the form (found at views/user_sessions/new.html.erb) for creating a new user session. That view expects you to provide a user session object as #user_session, which is accomplished in the controller's new action by the #user_session = UserSession.new statement. Without that line, the view is trying to render the form with a nil object reference, resulting in your error.
The create action handles the form submission that comes from new. It expects to see a hash of properties that are appropriate for a UserSession. UserSession.new is called with that hash of properties, creating a new UserSession populated with data from the submitted form. Calling save on the UserSession instance runs validations, which can potentially fail. You can see that if the save succeeds, the controller will redirect the user to the root URL with a "Success!" flash message. If it fails, it sends the user back to the form to fix their mistakes.

How to Route Multiple Pages to 'Edit' a Users Account Information (Rails)

I currently have a Ruby on Rails application with a typical User model. I would like to allow users to edit their own account information, and change their email or password. However, I would like to have the corresponding forms for this on two different pages.
There is a users_controller.rb which already has a show, new, create, and edit path. The problem is that using the edit path to update the User database would require all forms to be on the same page, which is inconvenient for users who only wish to update their email or password, and not both. Essentially, I need that edit path to be available on multiple pages.
Any suggestions?
Not possible. Only one action per named route.
You could use one named route plus an extra parameter to tell the controller which form (or parts of a form) to render:
named route path
edit_user_path(#user, :form => "info") mysite.com/users/1/edit?form=info
edit_user_path(#user, :form => "acct") mysite.com/users/1/edit?form=acct
edit_user_path(#user) mysite.com/users/1/edit
Then read this parameter and switch between templates depending on the value. No parameter will render the default view containing the full form:
def edit
# ...
case params[:form]
when "info"
render :template => "info_only"
when "acct"
render :template => "name_and_password"
else
render :action => :edit
end
end
I assume this is just for UX and not for security. All of these separate forms will PUT to the same update action, meaning all attributes accessible in one form (eg. password) will be accessible in another form.
Split the form up into separate .html.erb files (like email.html.erb and password.html.erb) and in your controller write something like:
def edit
...
if params[:email]
render 'email'
end
if params[:password]
render 'password'
end
end
Obviously the conditions can be whatever you want.

render :new not going to the right place after a validation

I have a 'new' form that gets validated in a post model. When the validator kicks in, it renders incorrectly.
The new post page path is at '/posts/new'
On validation, the new post page path is at '/posts' .. I need it to go back to '/posts/new'.
This is my controller:
def create
#post = current_user.posts.build(params[:post])
if #post.save
redirect_to public_post_page_path(#post.public_url)
else
render :action => :new
end
end
I have a feeling it might have to do with my form. So here is the formtastic first line:
<%= semantic_form_for [:student, post], :html => {:id => "post_form"} do |form| %>
This is the correct behavior from rails.
In the create action it simply renders the "new" view file. As such the url will be /posts but the view will correctly display the form. There is nothing wrong with this behavior; and in general rails convention is good form. Also the built in rails errors work if you just render new; however if you redirect they won't display.
If you really feel like you want to go back to that url you need to use:
redirect_to
instead of render.
If validation fails, user should see the form with the errors and stay at /posts/new. That's what you want, right?
There's a simple way to achieve this.
Set remote: true on the form to prevent the url from advancing. Handle ajax:success to replace the form on the page with the newly rendered one.
$('form[data-remote=true]').on 'ajax:success', (e, data, status, xhr) ->
if isHTML(data)
thisForm = "form[id=#{#getAttribute('id')}]"
$(thisForm).replaceWith $(data).find(thisForm)
isHtml() function is from this question.

Form_for Gives Wrong Outputs After render :action=>'edit'

I think this question might have been asked before, but I honestly don't know how to search for it.
Basically, when I do a render :action => 'edit' in the update action in controller, somehow the view outputs the form as if it's a :action => 'new' page.
form_for gave the wrong action and f.submit gave wrong button text (it gave create instead of update)
edit:
relevant parts of controller
def edit
#user = User.find_by_email(current_user.email)
end
def update
old_password=params[:user].delete(:old_password)
#user=User.new(params[:user])
if User.find_by_email(#user.email).valid_password?(old_password)
logger.info 'Valid old password'
else
flash[:notice]='Invalid current password'
render :action=>'edit'
end
end
As discussed in the comments, #bassneck is right - while you are rendering the edit view, the form_for call looks at whether the object is persisted or not (#user.persisted?). This has the benefit in a lot of cases of being able to use one piece of form code for both new and edit views (I'll generally have a partial _form.html.erb that gets used for both situations).
In your case though, it isn't leading to the desired behaviour - so wwhat you need to do is make sure you're using the relevant user object. If you want to update a user, #user should be the object you want to update.

Rails RESTful controller and rendering after custom action

How can I render after executing an action in a restful controller instead of redirecting.
I have a controller with standard actions, and I added a special action that adds data to the resource in question, via a form on the #show page (Think comments on a post). I am validating the input from the form and want to re-render the show action on error and redirect to the show action on success.
I want to render to save the user from inputting their info twice, but when I try to render the show action with an error in the flash[:notice] I get an error saying that I am not specifying an ID. When I do specify an ID, it tries to render a new template that doesn't exist yet.
I am thinking that it should be a as simple as:
def add_comment
if my_validation?
save the object
redirect_to :action => "show", :id => params[:id]
else
render :action => "show", :id => params[:id]
end
end
This is not my actual code, just something I put together just now as an example.
The best way is to re-render the :new
def create
#obj = TheObject.new(params[:object])
render :action => :new unless #obj.save
end
And in the new.html.erb
<% form_for :obj,
:url => object_url(#obj), :html => {:method => :post} do |f| %>
<%= f.text_field :name %>
<% end %>
That way, the inputs in the form will be pre-filled with what the user entered.
Create a new data object and add the values from the form, before you rerender, think it would work then. If you still get problems, try setting a boolean for editing new vs. existing rows, or create two different views entirely.
I've done it before but I don't quite remember how. Sometimes when I used the very typical use of the MVC pattern, it was allmost "automagical", othertimes (as I had to use an old quirky database) I had to code all the magic myself; sometimes usin the .new? function (or what it was called) on the ActiveRecord object, othertimes I used temporary "magic values" for ID (typically alphabetic strings for invalid id values.
(I appologize if I made some mistakes, it's a while since I coded Rails code...)

Resources