here is a frequent scenario: user has a dashboard in order to show some related information to the user. also, use can do some actions in his dashboard. according to abstraction, each of these actions, has its own controller and they are not all in the dashboard controller. for example, in order to update some information about user, you have user controller and not the dashboard controller. dashboard controller is only for rendering some information.
ok? now you have a form in your dashboard, posting the inputs to an arbitrary controller and we want to render the results(success message if succeeded and pre-populated form with errors if failed) in the dashboard. if we use redirect_to in the controller, we lose the validation errors and pre-population. if we use render, there will be uninstantiated variables in the dashboard template and we run into some errors.
what are the tricks to handle this?
P.S: there were some similiar questions but the answers were using render but it leads to the mentioned problem and doesn't work.
You could do it via ajax and remove/add appropriate html elements dependent on success/failure.
Or you could have
if #user.save?
redirect_to dashboard_path
else
#my_instance_variable = InstanceVariable.first
render "dashboard"
end
Related
So I'm working on a web application and I have a blog page, with two controllers, a posts controller for the blog and then a subscribers controller that simply allows the user to add a new subscriber. So currently I render the content using a view defined in posts, and then within that I have a partial, _subscriber, to handle the subscription model.
The problem comes when the user tries to subscribe. I want to be able to render the new action to show validations, like this:
def create
#subscriber = Subscriber.new(subscriber_params)
if #subscriber.save
flash[:success] = "Thank you for subscribing!"
redirect_to subscribers_url
else
render :new, status: :unprocessable_entity
end
end
Besides the fact that this results in a duplicate view (new.html.erb is identical to the partial), because it is not a partial view, it reloads the entire page and now replaces all of the post with just the subscription form. Currently, my workaround is to do a redirect when the user clicks the button, but then validation errors don't show and it isn't really an ideal solution.
I tried just rendering the partial, instead of the :new action, like this:
render partial: 'subscriber', status: :unprocessable_entity
But has the same effect as just calling redirect; my validation errors won't show.
Perhaps the ideal solution is to use something like AJAX. I tried to understand Turbo Frames and Turbo Streams, but I'm a little confused how I would implement that in this situation. Essentially, I could wrap the subscribe section of my posts page in a turbo frame but then how would I update the turbo frame? I don't want to have a different post page because that wouldn't make sense. I only want to change the content of the view inside.
What would the correct/best practices way of implementing this functionality be? Any suggestions would be appreciated!
If you don't want to actually reload the page, then yes, you'll need to do something with either AJAX / UJS or Turbo frames.
My favorite AJAX / UJS tutorial
A good Turbo tutorial
(Or go to the dark side with React or Node or some other JS solution)
Very general question I was hoping someone could clarify for me. I'm looking at the basic generated scaffold code for a model called products. I noticed the new and show actions in the controller don't have much written in them. In fact, show is entirely empty and new only has the line "#product = Product.new". I know these 2 actions are supposed to go to a separate view. A view to show the resource, and a new form view to input info and create a resource, respectively.
So, I'm curious how that actually happens. Other actions have redirect_to :some_path which makes sense, but how exactly does "render action 'show', location: #product " bring up the items show page when the action is empty? Also how is that different from redirect_to #product ?
thanks
Will
Render produces a string that will displayed as the response to the request to the application.
redirect_to produces a response header resulting in a new request to the application.
The render action 'show', location: #product uses the the file app/views/products/show.html.erb with #product as a parameter to produce the html which will be returned.
The reason some of the controller functions are empty is that rails are using defaults. So if you don't tell rails what to render then rails will look for a file in the appropriate location.
Methods ending with redirect_to are usually post/patch requests saving something in your database and after the requested action has been performed they redirect the user to a method meant for displaying information.
I want to have my form forward to recaptcha but only after form has passed all validation. How would I achieve this before users details are saved to DB?
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
#to recaptcha, but before save and only after sign up form passes validation
else
format.html { render :new }
format.js { render :form_errors }
end
end
end
Have a good look at The definitive guide to form-based website authentication and ask yourself if you really need a captcha.
Besides that, you can use Callbacks :after_validation, before_save, around_save, after_save, before_create, around_create, after_create, before_update, around_update, after_update to handle stuff still inside your transaction.
The way to call one of these callbacks is to simply declare them in your model
If you need to use a captcha however, I would do this with javascript and ajax, to append it to your form before the user sends it.
You should not do this in the controller after recieving a post of the form, since you will have to:
Store the filled form values in the session after validation (dont save)
Redirect the user to a captcha page (which will make any user confused)
Check the captcha multiple times before it passes (they are quite unreadable)
Get the model out of the session (which you have no idea of which one it is)
Call save on the model to actually write it to your DB.
So basically you avoid starting a transaction before the captcha is passed.
Validation lives in the model, you could simply do this in the controller:
#user.valid?
and then do your recaptcha stuff.
Another solution is to use callbacks such as: before_save or before_create but only if recaptcha could be accessed in model (which I doubt).
This Railscast has all you need to know about multistep forms. The episode covers validation and moving back and forth between steps. http://railscasts.com/episodes/217-multistep-forms
It sounds like your form has two steps, the first being where they enter in all their information, and the second being just a captcha entry.
Now, in my opinion you should just roll the captcha into the main user entry form and keep it all to a single page rather than having a two step process, I've done both before and having the captcha be part of the same form is much, much easier and less complex. Having everything in a single form allows you to have all of your logic consolidated (mostly) into a single controller action. There may be logic you can abstract out of the controller into a helper method, like the verification of the captcha, which will make your controller action that much less complicated. The last thing you want to do is over-complicate your action logic.
If you go to Twitter.com when you are not logged in, you will see the marketing page with the login & registration fields.
However, if you go there when you are logged in, you will see your activity stream for your Twitter handle.
I know one way to do this in Rails is to have a home/index for the logged in users, and just use public/index.html for the marketing site. But Twitter is not using public/index.html, so I am wondering how they do it?
Is it just a simple case of having one root route, but then an if statement that displays two different pages depending on whether or not the user is logged in?
Or is there some other more fancy routing trick that I can use to do that?
If it is just an if-statement, that seems a bit hacky...no?
Thanks.
This might give a head start. http://collectiveidea.com/blog/archives/2011/05/31/user-centric-routing-in-rails-3/
By default controller methods that handle specific routes render a view that has a corresponding name (home/index route links to home controller and index action which in turn renders the view index.html.erb inside the app/views/home folder).
However, inside the controller method that handles the root request you can simply render a different view based on the fact that a user is logged in or not.
You would probably have something like this:
class HomeController
def index
...
if user_logged_in?
render "logged_in_user"
# else it will render the index view by default
end
end
end
In this case "logged_in_user" would be a different view (template or html.erb file) from the app/views/home folder.
For more information take a look here: Rails rendering guide
it can some kind of redirect for not logged in users to different controller , checking of user session can be done in before_filter
I have my login-partial in my application.html.erb-layout.
Now I want to validate it, if the user pushes the submit button and show error-messages for it, if e.g. the passwordfield is empty.
But how do I do that?
For getting the error messages, I must use
render :action => 'create'
But there I have to know, from which action I came from. Beside different pages, need different seperate instance variables (which arn't reproduced with render :action).
Second try with
redirect_to :back
loses the errors-array...!
How can I solve this problem?
Found nothing in the net =(
So not a direct answer to your question, but I would skip rolling your own login and checkout something like the restful authentication plugin
script/plugin install git://github.com/technoweenie/restful-authentication.git
script/generate authenticated user sessions
I'm using restful_authentication!
and I'm including the login-partial into my appliation.html.erb layout...?!
Let me see if I get you correctly:
You have a login box in your application layout.
When you press the submit button you are posting to the create action of your session controller
If that's the case, you can just render the new action of your session controller and render that page as well.
So you can login from everypage, but if anything goes wrong you end up in the session controller new action.
Would that be an option?
Solved it - used Ajax-Forms!