Custom validation of Play 2.0 form (scala) - validation

I'm writing a little hobby app. Now, in my application I want people to have a userId (just like mine is niklassaers here on stack overflow), and if it is already taken, I want the user to get an error so he can select another.
Here follows my Signup object, it gives me an error at the line "mapping(": "missing arguments for method mapping in object Forms; follow this method with `_' if you want to treat it as a partially applied function"
object Signup extends Controller {
val userForm: Form[UserProfile] = Form(
mapping(
"userId" -> nonEmptyText,
"passwordHash" -> nonEmptyText,
"email" -> email
) verifying (
"ThisIsATest", { case(userId, passwordHash, email) => true }
// "UserID already taken", { DBService.exists(UserProfile.getClass().getName(), userId) }
)(UserProfile.apply)(UserProfile.unapply))
def index = Action {
Ok(views.html.signup(userForm))
}
def register = Action { implicit request =>
userForm.bindFromRequest.fold(
errors => BadRequest(views.html.signup(errors)),
user => Redirect(routes.Profile.index))
}
}
As you can see, I've replaced my lookup service with a test verification that simply returns true, to make the example less complex. For completeness, this is my UserDetail case class:
case class UserProfile(
userId : String,
email: String,
passwordHash: String)
I'm a Scala newbie and Play newbie, so I'm sorry if this is a very trivial question. But:
What am I doing wrong since I get this error?
Is this the right way of adding my own validation?
Follow-up question: I redirect if it goes well, but how should I redirect to a page referencing the just verified form?
Cheers
Nik

Finally got around this: verifying isn't something that comes after mapping, it is something that comes at the constraint. So it should be
"userId" -> nonEmptyText.verifying( "UserID already taken", userId => DBService.exists(UserProfile.getClass().getName().replace("$", ""), userId) == false ),
I hope this helps others that have the same problem :-)

A little late, but anyway..
You can do validation on the whole "form-backing object" instead of just a single field as you ended up with. This is similar to the first code you posted in your problem description. The problem is that your verifying block needs to be after the apply/unapply statements.
case class UserRegistration(username: String, password1: String, password2: String)
val loginForm = Form(
mapping(
"username" -> email,
"password1" -> text,
"password2" -> text
)
(UserRegistration.apply)(UserRegistration.unapply)
verifying ("Passwords must match", f => f.password1 == f.password2)
)

Even later, but anyway... :)
Using verifying on the entire "form backing object" doesn´t let you add errors to individual fields in the form. If you want to do that see Play! framework 2.0: Validate field in forms using other fields

Related

Confused about Laravel "sometimes" validation works

I'm really confused about why this is happening? I had successfully added a record then when I tried to update the record It says that the field is required even I passing it already. Then when I tried to add "sometimes" on the validation. Now, it works. Why? Please enlighten me. Thank you!
my Test Model
This was the result when I tried to remove "sometimes"
As per the doc sometimes is used for :
Validating When Present In some situations, you may wish to run
validation checks against a field only if that field is present in the
input array. To quickly accomplish this, add the sometimes rule to
your rule list:
$v = Validator::make($data, [
'email' => 'sometimes|required|email', ]);
Therefore since the request is not containing the expected fields, the validation is successful
Adding sometimes effectively disables the required rule and allows the client to simply not pass that field into the input.
In your case, the validator is probably not receiving the correct data from input. Because If it did, the required rule would act correctly.
Please post the code of your validator to be able to debug the problem.
sometimes is when you sometimes include the field.
Let's see an example of validation when creating a user:-
$validation = [
"name" => "required|string|",
"email" => "required|email",
"hobbies" => "sometimes|array"
];
Sample payloads
{
name: "Bob",
email: "bob#gmail.com"
}
// this will pass
{
name: "Bob",
email: "bob#gmail.com",
hobbies: ["fishing", "swimming"]
}
// this would also pass
{
name: "Bob",
email: "bob#gmail.com",
hobbies: "swimming"
}
// this would fail since it doesn't match "array" validation

redux-form initialize FieldArray

I'm trying to create a redux form which integrates many aspects of redux-form.
To give a better introduction to the project I would like to share the main goals with you.
At the moment i've a dynamic form which can be extended with participants. Each participant has a superior. On user input (Async.Creatable React select) I request (call to API) all users based on the text. To sum up, an Autosuggestion. When receiving the users I make a second call to get the corresponding superior. Afterwards I would like to autofill the fields for the participant as well as for the superior.
Everything works quite well for the first participant + superior. Unlike the first participant the second superior is not getting autofilled.
Is it required to call the initialize action (redux-form) manual, when mutating the initalValues Property?
The function getFormData access the current state. These state is as expected and contains the following data.
These state is created with the LOAD action of redux-form
initial
:
attendees
:
Array(2) <-- Autofilled fields [{name: FirstTest, firstName: FirstTest}, {name: SecondTest, firstName: SecondTest}]
const mapStateToProps = (state) => {
const attendeesFromFormData = getFormData(state, REGISTRATION_FORM, [{}]).attendees
const attendees = attendeesFromFormData ? attendeesFromFormData : [{}]
return {
initialValues: {
attendees: attendees
}
}
}
export default connect(mapStateToProps, {searchADUser, autoFillAttendee, getADUser})(reduxForm({
form: REGISTRATION_FORM,
enableReinitialize: true
})(RegistrationForm))
Okay after a bit research and testing I find a simple solution for my problem.
Each time you add a participant you have to initialize manually the redux-form.

Odata query won't expand

I'm querying my service using a url like:
http://a.com:3080/odata/DiscussionVM(6)?$expand=Section,User
on controller method:
[EnableQuery(MaxExpansionDepth = 7)]
public SingleResult<DiscussionVM> GetDiscussionVM([FromODataUri] int key)
{
return SingleResult.Create(db.DiscussionVMs.Where(discussionVM => discussionVM.DiscussionId == key));
}
This works and returns the correct JSON.
However I then run the slightly more advanced query on a different model:
http://a.com:3080/odata/OrganisationVM(30)?&$expand=Categories($expand=Discussions($expand=Section,User))
and controller action:
// GET: odata/OrganisationVM(5)
[EnableQuery(MaxExpansionDepth = 5, AllowedQueryOptions = AllowedQueryOptions.All)]
public SingleResult<OrganisationVM> Get([FromODataUri] int key)
{
return SingleResult.Create(db.OrganisationVMs.Where(organisationVM => organisationVM.OrganisationId == key));
}
this returns the below DiscussionVM JSON:
{
#odata.type: "#Models.DiscussionVM",
DiscussionId: 6,
Section_SectionID: 1005,
User_Id: "4cecc52e-ac3a-4696-ac6c-175af2a6378a",
DateCreated: "2014-12-06T00:00:00Z",
OrgCat_OrganisationCategoryId: 1,
Text: "Dummy section",
Html: null,
IsUserCreated: true,
Organisation_OrganisationId: null,
Positives: null,
Negatives: null,
CommentCount: 1
}
But contains no User or Section object. No error is thrown. The correct objects are queried (profiled) in the database and data including user and section are returned.
I discovred that oData needs the expanded entities to be referenced in its Edm Model.
if not it will stop expanding after the first level, that's why further expands will not work.
Just add your expandable EntitySet to the ODataConventionModelBuilder in your IEdmModel (in MapODataServiceRoute's model config) :
var builder = new ODataConventionModelBuilder();
// ...
builder.EntitySet<Categories>("categories");
// ...
Hope this helps.
From what Brad and I have gathered in this SO answer, it could be a matter of mixing complex types with entity types. Expand plays very well if all your types are entities, but if you mix both, you end up with weird behavior like you and I are having.
If you do mix them, the expand cascade has to start with entity types and end with complex types. The expand chain seems to end where a complex type has an entity type property.
This could come from v3 where a complex type referring to an entity type was flat not supported. It is in V4 but it is not totally clean with WebAPI as we can see.
The lack of documentation and support on the matter makes it difficult to claim this is the absolute truth, but at least it explained my situation and made my stuff work. Hope it helps you too.
I have never seen your $expand syntax before. Where did you get it from? I think you must expand your query the following way:
http://a.com:3080/odata/OrganisationVM(30)?$expand=Categories/Discussions/Section,Categories/Discussions/User
Assuming Odata V4, here are some examples of the standard.

ASP.NET WebForms FriendlyUrlSegments does not contain a constructor that takes 0 arguments

I'm doing a simple test with FriendlyUrls in ASP.NET 4.5 WebForms, Foo.aspx becomes /Foo/ (it works).
When I try to use FriendlyUrlSegments Attribute to get the id from URL into the control I get this error:
'Microsoft.AspNet.FriendlyUrls.ModelBinding.FriendlyUrlSegmentsAttribute' does not contain a constructor that takes 0 arguments
method that has the [FriendlyUrlSegments] error:
public Person GetPerson([FriendlyUrlSegments]int? id)
{
return People.Find(p => p.Id == id);
}
I have tried to update FriendlyUrls from NuGet.
Write your method like so:
public Person GetPerson([FriendlyUrlSegments(0)] int? id)
{
return People.Find(p => p.Id == id);
}
The [FriendlyUrlSegments] attribute uses a zero-indexed map of segments after the page in the URL. For example, if you request /Hello/foo/bar/... and your page is Hello.aspx, then [FriendlyUrlSegments(0)] will map to "foo", [FriendlyUrlSegments(1)] will map to "bar", and so on.
I think the way you did is model binding not for get information from url.
I read this article
of scott hanselman and i try it. I had the same issue with you. And i thought [FriendlyUrlSegments]int? id
for Model binding. Instead of that i did this:
var id=Request.GetFriendlyUrlSegments()[0];
yourmethod(id);
Please feel free to correct me if i'm wrong!
Hope this help.

Storing Session Variables in Lift Scala

I am trying to store a session variable and then use it to modify the menu in Boot.scala. Here is how I am storing the variable in a snippet:
object sessionUserType extends SessionVar[String](null)
def list (xhtml : NodeSeq) : NodeSeq = {
Helpers.bind("sendTo", xhtml,
"provider" -> SHtml.link("/providerlogin",() => sessionUserType("provider"), Text("Provider")),
"student" -> SHtml.link("/studentlogin",() => sessionUserType("student"), Text("Student")))
}
Then in Boot.scala I do this:
val studentSessionType = If(() => S.getSessionAttribute("sessionUserType").open_!.equals("student"),
"not a student session")
I also tried to call the object by name (sessionUserType), but it can never find it, so I thought this might work, but I keep getting an empty box when i access it even though the actual binding and function get executed prior to the menu rendering.
Any help would be much appreciated.
Thanks
In order to get a value from SessionVar or RequestVar, call is method on it, i.e. sessionUserType.is
By the way, did you read "Managing State"?
Side note
I believe RequestVar is a better fit in your case. I am not sure I could catch your code right without the context, but it could be rewritten at least like:
case class LoginType
case object StudentLogin extends LoginType
case object ProviderLogin extends LoginType
object loginType extends RequestVar[Box[LoginType]](Empty)
// RequestVar is a storage with request-level scope
...
"provider" -> SHtml.link("/providerlogin",() => loginType(Full(ProviderLogin)), Text("Provider")),
// `SHtml.link` works in this way. Your closure will be called after a user
// transition, that is when /providerlogin is loading.
...
val studentSessionType = If(() => { loginType.is map {_ == StudentLogin} openOr false },
"not a student session")
// As a result, this test will be true if our RequestVar holds StudentLogin,
// but it will be so for one page only (/studentlogin I guess). If you want
// scope to be session-wide, use SessionVar
I think the disconnect is that you are assuming that the a Session Attribute is going to match your SessionVar, and that is not the case. Lift is a very secure framework, and one if its features is that Lift creates opaque GUIDs to refer to components on the
server side.
If you want getSessionAttribute to return something, think about how you can call setSessionAttribute.

Resources