I am using Symfony 1.4 forms for a simple login module. The form, pretty basic has it's code listed below:
<?php
class LoginForm extends sfFormSymfony
{
public function configure()
{
$this->setWidgets(
array('username' => new sfWidgetFormInputText(),
'password' => new sfWidgetFormInputPassword(),));
// 'remember_me' => new sfWidgetFormSelectCheckbox(array('choices'=>array('true'=>''))),));
$this->widgetSchema->setNameFormat('login[%s]');
$this->setValidators(array(
'username' => new sfValidatorString(array('required'=>true)),
'password' => new sfValidatorString(array('required'=>true)),
));
}
}
The form renders fine in the template page as expected. FYI, I use $form['username']->render method to individually render the methods where I like them instead of echoing the form out.
Upon post (recognized) I bind values to the form like this:
$this->form->bind($request->getParameter('login'));
However, it fails against the condition
$this->form->isValid();
Both the fields are not being left empty and the credentials are correct, so this seems something more insidious to me.
Upon doing a var_dump($this->form->getValues()); it returns an empty array which I believe implies that the values were not retrieve nor bound.
Can anybody spot where I possibly am messing up ?
Thanks
As of symfony 1.3, csrf protection is enabled by default. This means that all your forms get a csrf token field, named _csrf_token by default - it's a hidden field that's unique to your session and the given form type.
If you don't render and submit this field with the rest of your form it will be invalid - it detects a csrf attack, so it's good this way.
The short fix is to render the token field:
echo $form["_csrf_token"]->render();
But the better way is to render all hidden fields in one go (I usually did this next to the submit button):
echo $form->renderHiddenFields();
If you really need to, you can use a little snippet to display errors like this:
foreach ($this->getErrorSchema() as $field => $error) {
if ($error instanceof sfValidatorErrorSchema) {
foreach ($error as $field => $error) break;
}
echo $field . ' => ' . $error; // e.g. "Field name" => "Error message".
}
#Maerlyn resolved this. For future reference:
The form fields were being rendered individually instead of using vanilla echo $form. Because of this, I did not render $form['_csrf_token']->render() which should have been done. Due to which the login failed. Render the csrf_token field as well and you are good to go.
Related
I have a requirement when creating a new Foo object and a unique field foo_id exist already, I have to redirect to the edit page for that foo_id.
I'm using jQuery autocomplete with the foo_id textbox already and was wondering what the best way to do this?
My initial thought is to return an extra isExist attribute in the JSON that gets returned to jQuery autocomplete and based onselecting a foo_id, I'll check the isExist attribute and redirect.
Is there a better way to do this? Also, if I need to do a redirect from JavaScript, should I generate the path from Rails?
Based on Vidya's answer and found results from other questions, this is what I did:
in Foo's controller added:
def checkFooExists
#foo = Foo.find_by_foo_id params[:foo_id]
if !#foo.nil?
flash[:notice] = 'You entered an existing Foo ID, so here is the edit page'
flash.keep(:notice)
render :js => "window.location = '" + edit_foo_path(#foo) + "'"
else
render :nothing => true, :status => 409
end
end
in routes change:
#resources :foos
resources :foos do
collection do
get 'checkFooExists'
end
end
in application.js, in the autocomplete event handler for select for textbox add one jQuery get line:
select: function(event, ui) {
$.get("/foos/checkFooExists", { foo_id: ui.item.foo_id });
$('#bar').val(ui.item.bar);
return false;
}
There are a lot of ways to do this, but an easy way would be to send an ajax GET request (on the change event for the autocomplete) with the id of the selected Foo instance to a controller endpoint. Do a lookup with the id. If an instance with the id exists, return a 200; otherwise, return a 404. So you would have success and error handlers respectively to handle those cases.
At this point, you can do many more things. Your REST endpoint could send the result of foo_path(foo) (remember you looked up foo) in the body of the 200 response. You could keep a list on the client side of all the different foo_path(:id)s corresponding to the choices in your autocomplete and pick the right one on success. Either way, you can then set document.location in your JavaScript to the correct path.
And probably a lot of other things others will point out I'm sure.
I'm new to Ruby so please excuse my ignorance. I really didn't know how to word this question so this may also be part of the reason I haven't found an answer online.
I'm working with Rho Elements, and I'm trying to pass something from one page to another. I've made some good headway but run into something that I do not understand. I can pass through an ID like so
<input type="hidden" name="id" value="<%= #orderdetails.object %>"/>
I then grab the ID(only doing this right now to make sure I do get the ID)
#id = #params['id']
then redirect to another page
redirect url_for(:action => :newpage, :id => #id).
This is where my problems start. When I debug the application I get past the redirect and enter :newpage
def newpage
#orderdetails = OrderDetails.find(#params['id'])
if #orderdetails
render :action => :newpage, :back => url_for(:action => :index)
else
redirect :action => :index
end
end
Once here I check
#params['id]
and this is what is displayed.
#params {"id"=>"{131113212443313.17}"}
"id" ""
#params {"id"=>"{131113212443313.17}"} is shown by eclipse and when I break into the variable "id" "" is shown.
Why can I see the ID that I want to use to grab the orderdetails that was just created but also have the actual variable be empty?
**EDIT: This is the information I'm trying to pass.
#params {"id"=>"131113212443313.17", "next"=>"asleftnext", "orderdetails"=>
{"AsFoundMeterRead"=>"", "AsFoundImage"=>""}}
"id" "131113212443313.17"
"next" "asleftnext"
"orderdetails" {"AsFoundMeterRead"=>"","AsFoundImage"=>""}
Use params in the controller, not #params. Also the canonical form of accessing keys is params[:id].
Like its say in the previous answer you access the params in the controller in this way
#id = params[:id]
Also if you are using Rails 3 or higher you may want to use the new url way is less verbose so its more easy to read.
newpage_controllername_url(:id => #id)
you can also ask for the path with this method.
If you don't know if you are passing right the params you can display the content using
params.inspect
You can view the content of any object with inspect
I'm new to Ruby on Rails and i have an issue.
I have 2 forms which edit the same model, but in the update method I have to give a different JS response depending on the form which submitted.
How do I do that?
Just add a hidden input field to your form specifying where it comes from.
Then, in your controller, access this field through the params[:field_name].
Create the form by using something like:
<%= f.hidden_field :origin, :value => "this_form" %>
This will render as something like:
<input name="origin" type="hidden" value="foo"/>
In your controller, check which value this hidden field had, and use render to render your JS response (or whatever you specifically use). See Layouts and Rendering for more info.
if params[:origin] == "foo"
render ...
else
render ...
end
There are two different ways you could go about this:
You could put a hidden variable in the form and then check in the controller to see which form was submitted.
You could also have two different controller methods to handle the different behavior.
Without knowing more about your code it's hard to say which way would be cleaner.
I apologize for sounding daft in advance, but I recently discovered JSON in Rails and I'm really interested in creating a form that is broken up through several pages. The data would then be carried from page to page through a JSON object.
I'm stuck on how to properly to do that.
My first page of the form is this :
First Page
Controller:
def create
# removed some code here for the sake of simplicity
if #card_signup.save
respond_to do |wants|
wants.html {}
wants.json { render :json => { :html => (render_to_string :partial => 'final_form')}}
end
else
respond_to do |wants|
wants.html { render :new }
wants.json { render :json => { :errors => #card_signup.errors } }
end
end
end
The Javascript that handles saving the first form to this controller
$(".step_two_submit").click(function(){
$("#new_card_signup").attr("action", function(index, action) {
var values = [],
getKey;
$("#sortable").sortable('serialize').replace(/(\w+?)\[]=(\d+?)/g, function(all, key, number) {
values.push(number);
getKey = key;
});
var cardSignupGetParams = 'card_signup=' + getKey + '[' + values.join(', ') + ']';
return action + '?' + cardSignupGetParams + "&foo[]=bar";
});
});
Here's the tough part! I want to make it so that I validate if this form was written correctly as usual. No problem, the form is set up to do that. But when they click next, I want them to go to a second form which is a disclaimer they have to agree to before the Object is saved.
So if they back out, or don't approve of the disclaimer, the Object will have never been created.
To accomplish this.. I assume I need to instead of saving the object, I need to store the object in a JSON object and carry it over via AJAX to this next AJAX loaded disclaimer page.
Does anyone know how I might be able to splice that together?
Again, I apologize if this doesn't make much sense.
What you really want to do is validate the object before you go to the second part of the page. If you definitely want to make a round trip to the server, you can use #card_signup.valid? instead of #card_signup.save in the controller of your "check" action, and then just hide the form elements with javascript and show your disclaimer. This way you are still checking that it would save when it's finally submitted, but not actually saving it into the database.
Another way to do this without javascript would be to have the first page submit to the controller action that just checked for a valid object, and go to a second page which then renders most of the form elements as hidden elements, effectively carrying the filled-in form to the second page without saving it.
Alternately, you can do the validation on the client side as much as possible and not hit the server. See the Client Side Validations railscast for an interesting and easy-ish way to get this done.
A question about symfony form validators. For example I have an url field. If the user leave this field empty, it is OK. But if the user provide an url, he should provide a valid one.
I tried $this->setValidator('url', new sfValidatorUrl(array(), array('invalid' => 'invalid url')));. But it doesn't permit empty values. (which is not the desired behavior)
In another word. I need a Null-Or-Valid validator. I prefer not to write a new validator myself. I think I should be able to combine some validators to achieve my goal.
just set the "required" option to false (by default, it is true).
$this->setValidator('url',
new sfValidatorUrl(array('required' => false), array(
'invalid' => 'invalid url')));
Try the URL validator I wrote. It not only validates but sanitizes.
http://jasonswett.net/how-to-validate-and-sanitize-a-url-in-symfony/