rails different form_for parameters for different tasks? - ruby

I have the following two form_for() that I am confused about.
# form for users
form_for(#user) do |f|
# form for sessions
form_for(:sessions, url: login_path) do |f|
I understand that the first one is simply go through all the users and input the form. I am not sure why when you create a new session, the parameters for form_for is listed as such. Why is there a login path?
Michael Hartl explained it as "in the case of sessions we need to indicate the name of the resource and the corresponding URL", but that doesnt' really explain anything to me.
any enlightenment would be nice!

Passing :url to form_for method is optional when dealing with a model object. when using it to create a new object:
# long-style:
form_for(#user, url: users_path)
# same thing, short-style (record identification gets used)
form_for(#user)
In the short-style version a concept called Record Indentification is used, basically rails figures out if the record is new by asking record.new_record? It also selects the correct path to submit to based on the class of the object, in this case #user.class
Same principle applies when using form_for when updating an existing object. In this case the record.new_record? returns false, and rails figures out it must submit the form to the update action of the controller.
In cases when the path that the form must submit to cannot be figured out by rails using the above mechanism, then the url must be provided explicitly. This also applies when defining Singular Resources such as resource :geocoder. when creating forms for singular routes, the URL must be specified:
form_for #geocoder, url: geocoder_path do |f|

In the first case, the form_for helper inspects the #user variable to see its state. The User might be a new record (in which case the form points to /users with POST*) or an existing record (users/:id with PATCH). It can also provide pre-filled inputs based on the variable's state.
The second form is used when there's no need for an instance of a model (or maybe the model doesn't even exists) and the form_for helper is used just for convenience. The url parameter is explicitly set because by default the action would point to the current URL and you want it to point to login_path.
*Technically they are both POST on the browser side, Rails will distinguish between them later.

Related

Redirect to another model's index action, and hence view index.erb - Rhomobile

I am developing a Rhomobile application,on submit of a POST method, i am going to my 'Model 1' action, after execution of my action i want to redirect to another model's (Model 2) Index action and list the data.
I am from a Rails background, there i would have used URL, any similar concept exists here or any solution.
i tried, but it didn't worked for me render :controller => :model2, :action => :index
Please Note: I have never used rhodes and all of this information was acquired by simply reading the API documentation and taking a look at the source code.
According to the documentation You should be able to deal with this in a very railsy fashion eg
def some_action
redirect controller: :model2, action: :index
end
Seems the only caveat is if this redirection is to happen in a callback function. In this case the redirection should be handled by the WebView instead e.g.
Rho::WebView.navigate(url_for(controller: :model2 action: :index))
Source for Rho::RhoController#redirect supports these statements in the documentation.
Additionally as you might notice above it appears that Rho has ported a lot of the rails like helpers including url_for

How rails form instance works?

I have these two methods, show and create.
def show
#article = Article.find(params[:id])
#comment = Comment.new
#comment.article_id = #article.id
end
def create
#comment = Comment.new(comment_params)
#comment.article_id = params[:article_id]
#comment.save
redirect_to article_path(#comment.article)
end
Show method displays my comment form.
In the show method why do we create a new instance of Comment and also associate the comment
instance to an article id.
Create method actually handles the submission of form.
In the create method, again i am creating a new comment object and again associating the comment's article_id.
My whole questing is why were repeating these things?. Why do I have associate my comment form with article_id when I am displaying it and again I am repeating the steps while submitting the form too.
This repetition could be avoided if you keep those resources nested and build the form as:
<%= form_for(#article, #article.comments.build) do |f| %>
Hope this helps! :)
The reason that you initialize a comment both times is because the user's browser only sees the html form - it doesn't have a concept of a Comment - and because each request to a Rails application is independent - nothing is persisted in the application between requests:
When the user requests the show page for an Article, the request is handled by the application something like this:
The controller creates a new Comment object (in memory).
The form_for helpers in the view build a form from that Comment.
The html for the show page is sent to the user's browser.
At this point the application has done everything it needs to serve this request, so the temporary Comment object is deleted.
When the user submits the form, the values that were entered are sent to the application in the comment_params and the application handles this request like this:
The controller creates a new Comment object (again in memory), but initializes it with the data that the user sent through in comment_params.
The controller saves the Comment - this stores the Comment in the database so it can be loaded later.
The controller redirects back to the show page.
Saving to the database is the main way that the application can persist things between requests - objects in memory only exist while the request is being processed.

MongoMapper default values and simple_form

I have a Character model which has some defaults and have created a simple form for it (or rather a subclass of the Character model) all tied together by a controller.
The problem is that the form does not get the default values when called by simple_form_for Character.new.
Have I missed some configuration flag I need to set or do I have to edit the simple_form templates?
there is an open pull request for this issue: https://github.com/jnunemaker/mongomapper/pull/393
so you should wait a bit before it will be merged :)
BTW, it's not a SimpleForm issue but rails form_for.

Make the route parameter actually appear in the address bar

I have a tiny application in MVC 3.
In this tiny application, I want my URLs very clear and consistent.
There's just one controller with one action with one parameter.
If no value is provided (that is, / is requested by the browser), then a form is displayed to collect that single value. If a value is provided, a page is rendered.
The only route is this one:
routes.MapRoute(
"Default",
"{account}",
new { controller = "Main", action = "Index", account = UrlParameter.Optional }
);
This all works fine, but the account parameter never appears in the address line as a part of the URL. I can manually type test.com/some_account and it will work, but other than that, the account goes as a post parameter and therefore does not appear. And if I use FormMethods.Get in my form, I get ?account=whatever appended to the URL, which is also not what I want and which goes against my understanding. My understanding was that the MVC framework would try to use parameters set in the route, and only if not found, it would append them after the ?.
I've tried various flavours of setting the routes -- one route with a default parameter, or one route with a required parameter, or two routes (one with a required parameter and one without parameters); I've tried mixing HttpGet/HttpPost in all possible ways; I've tried using single action method with optional parameter string account = null and using two action methods (one with parameter, one without), but I simply can't get the thing appear in the URL.
I have also consulted the Steven Sanderson's book on MVC 3, but on the screenshots there are no parameters either (a details page for Kayak is displayed, but the URL in the address bar is htpp://localhost:XXXX/).
The only thing that definitely works and does what I want is
return RedirectToAction("Index", new { account = "whatever" });
But in order to do it, I have to first check the raw incoming URL and do not redirect if it already contains an account in it, otherwise it is an infinite loop. This seems way too strange and unnecessary.
What is the correct way to make account always appear as a part of the URL?
My understanding was that the MVC framework would try to use
parameters set in the route, and only if not found, it would append
them after the ?
Your understanding is not correct. ASP.NET MVC doesn't append anything. It's the client browser sending the form submission as defined in the HTML specification:
The method attribute of the FORM element specifies the HTTP method used
to send the form to the processing agent. This attribute may take two
values:
get: With the HTTP "get" method, the form data set is appended to the URI specified by the action attribute (with a question-mark ("?")
as separator) and this new URI is sent to the processing agent.
post: With the HTTP "post" method, the form data set is included in the body of the form and sent to the processing agent.
ASP.NET MVC routes are used to parse an incoming client HTTP request and redispatch it to the corresponding controller actions. They are also used by HTML helpers such as Html.ActionLink or Html.BeginForm to generate correct routes. It's just that for your specific scenario where you need to submit a user entered value as part of the url path (not query string) the HTML specification has nothing to offer you.
So, if you want to fight against the HTML specification you will have to use other tools: javascript. So you could use GET method and subscribe to the submit handler of the form and inside it manipulate the url so the value that was appended after the ? satisfy your requirements.
Don't think of this as ASP.NET MVC and routes and stuff. Think of it as a simple HTML page (which is what the browser sees of course) and start tackling the problem from that side. How would you in a simple HTML page achieve this?

Django Forms - Processing GET Requests

We have an existing Django form that accepts GET requests to allow users to bookmark their resulting query parameters. The form contains many fields, most of which are required. The form uses semi-standard boilerplate for handling the request, substituting GET for POST:
if request.method == 'GET':
form = myForm(request.GET)
if form.isValid()
# Gather fields together into query.
else
form = myForm()
The problem is that the first time the form is loaded, there's nothing in the GET request to populate the required fields with, so most of the form lights up with 'missing field' errors.
Setting initial values doesn't work; apparently, the non-existent values in the GET request override them.
How can we avoid this? I'm pretty certain we're simply not processing things correctly, but I can't find an example of a form that handles GET requests. We want errors to show up if the user hits the "Submit" button while fields are blank or otherwise invalid, but don't want these errors showing up when the form is initially displayed.
The positional argument to the forms.Form subclass informs Django that you intend to process a form rather than just display a blank/default form. Your if request.method == 'GET' isn't making the distinction that you want because regular old web requests by typing a URL in a web browser or clicking a link are also GET requests, so request.method is equal to GET either way.
You need some differentiating mechanism such that you can tell the difference between a form display and a form process.
Ideas:
If your processing is done via. AJAX, you could use if request.is_ajax() as your conditional.
Alternatively, you could include a GET token that signifies that the request is processing. Under this example, first you'd need something in your form:
<input type="hidden" name="action" value="process_form" />
And then you can look for that value in your view:
if 'action' in request.GET and request.GET['action'] == 'process_form':
form = myForm(request.GET)
if form.is_valid():
# form processing code
else:
form = myForm()
I'll also give you the standard, boilerplate point that it's generally preferable not to use GET for form processing if you can help it (precisely because you run into difficulties like this since you're using an anomalous pattern), but if you have a use case where you really need it, then you really need it. You know your needs better than I do. :-)
If your clean page load doesn't have any non form GET params, you can differentiate between a clean page load and a form submit in your view. Instead of the usual
form = YourForm()
if request.POST:
you can do
if request.GET.items():
form = YourForm(request.GET)
if form.is_valid():
...
else:
form = YourForm()
If your clean page load could have other params (eg email link tracking params) you'll need to use the QueryDict methods to test if any of your form params are in the request.
request.GET is and empty dictionary when you first load a clean form. Once you have submitted the form, request.GET will be populated with your fields data, even if the fields contain only empty data.
My first question is this, which I posted as comment:
Why not just use request.POST and the standard way of processing form data?
After considering everything here, perhaps what you are looking for is a way of processing data in your query string to populate a form. You can do that without using request.GET as your form.data.
In my own views, I take advantage of a utility function I created to add initial data to the form from request.GET, but I am not going to share that function here. Here's the signature, though. initial_dict is typically request.GET. model_forms is either a single ModelForm or a list of ModelForm.
def process_initial_data(model_forms, initial_dict):
Nevertheless, I am able to process the form through the standard practice of using request.POST when the form is POSTed. And I don't have to pass around all kinds of information in the URL query string or modify it with JavaScript as the user enters information.

Resources