Grails use Command Object and object in the same gsp - grails

I have a controller, edit method paint the user info in the form file. But
when I try to update with errors the command object return userCommand object so I lost all info from user object.
Is there any way to use both in the same form? or what I'm missing here.
UserController class
class UserController {
def edit(User user) {
respond user
}
def update(UserCommand userCommand) {
log.debug "Update a User"
if (userCommand.hasErrors()) {
respond userCommand.errors, view: 'edit'
return
}
}
}
_form.gsp file
<g:form action="update">
<div class="form-group">
<label for="firstName">User First Name</label>
<input class="form-control" name="firstName" value="${user?.firstName}">
</div>
<div class="form-group">
<label for="lastName">User Last Name</label>
<input class="form-control" name="lastName" value="${user?.lastName}">
</div>
</g:form>

You should use UserCommand on both actions parameter and create your User object inside the action from UserCommand by data binding. This is to separate your View Model from the actual Model.
Like other users stated, return the whole UserCommand instead of UserCommand.errors. You can access UserCommand.errors in the view also.
Remember, that after your UserCommand is valid, you still need to create User and validate it and return any errors it has. Both can be run through <g:renderErrors bean="${user}"> for example.

Thank you #tuomas-valtonen. You drive me to find the solution.
def edit(User user) {
UserCommand userCommand = new UserCommand()
bindData(userCommand, user)
respond userCommand
}

Related

Action in grails form is not working

I am trying to make a simple creation of account and when create button is clicked it should perform the action "create" but I get an error saying that
HTTP Status 404 - "/WEB-INF/grails-app/views/users/create.gsp" not found.
Here is my code block for the index.gsp
<!-- CREATEFORM -->
<div id="id02" class="modal">
<g:form class="modal-content animate" controller="users" action="create">
<div class="imgcontainer">
<span onclick="document.getElementById('id02').style.display='none'" class="close" title="Close Modal">×</span>
<div class="container" style="text-align:center">
<b><h style="font-family: Arial, Helvetica, sans-serif; font-size: 30px">CREATE AN ACCOUNT</h></b><br/>
<input type="text" placeholder="Enter Username" name="uname" required/>
<input type="password" placeholder="Enter Password" name="psw" required/>
<input type="text" placeholder="First Name" name="firstName" required/>
<input type="text" placeholder="Last Name" name="lastName" required/>
<input type="text" placeholder="Age" name="age" required/>
<br/>
<input type="date" placeholder="Birth Date" name="birthdate" required/>
<br/>
<input type="text" placeholder="Student Number" name="studno" required/><br/>
<label>
<input type="checkbox" checked="checked" name="remember"> Remember me</input>
</label>
<br/>
<button type="submit" style="width: 100px; margin-right:10px;" >Create</input>
<button type="button" onclick="document.getElementById('id02').style.display='none'" class="cancelbtn">Cancel</button>
</div>
</div>
</g:form>
</div>
and Here is my code block for the usersController.
class usersController {
def index(){}
def create()
{
new Users(userid:params.uname,password:params.psw).save()
new UserInfo(studentno:params.studno,age:params.age,birth_date:params.birthdate,first_name:params.firstName,last_name:params.lastName,user_id:params.uname).save()
}
}
And here's the error
HTTP Status 404 - "/WEB-INF/grails-app/views/users/create.gsp" not found.
Because you are saving data using create action but after saving data there is no redirect option or create.gsp available. So grails will look first is there any redirect option available and try to redirect create.gsp
Check bellow code changes which will save user id to userInfo table and redirect to index page
So change your usersController
class usersController {
def index() {}
def create() {
def user = new Users(userid: params.uname, password: params.psw).save()
def userInfo = new UserInfo(studentno: params.studno, age: params.age, birth_date: params.birthdate, first_name: params.firstName, last_name: params.lastName, user_id: user.id).save()
if (user && userInfo) {
flash.message = "User created successfully"
redirect action: 'index'
} else {
flash.message = "Problem in user creation"
redirect action: 'index'
}
}
}
And add bellow code to your index.gsp
${flash.message}
There are many ways to redirect to pages. You can use render, redirect, chain, forward ..etc
Please check grails documentation for more information
In Grails for action (non gsp) you need to render something to the client,
otherwise it executes everything inside that action, but returns 404 gsp not found response, if there is no render / redirection statement it consider that action as a gsp but it is not gsp actually, therefore it responds 404.
You could render something data like list / JSON or simple string as follows.
def create() {
//your business logic is here
render "operation performed successfully"
}
First of all what grails version do you use? If the latest one (3.3.4) so this link might be helpful.
Speaking shortly: if you don't specify what to render explicitly - grails tries to find the view to display the result of action execution as:
grails-app/views/<controllerName>/<actionName>.gsp
Looks like you don't have one.
UPD
There are several ways to render action's output in grails controller.
Define explicit content as:
def myAction() {
...
render "Hello World!"
}
That will result in "white screen" with "Hello world!" text in top-left corner.
Another option is to create a gsp view in the conventional location as grails-app/views//.gsp - it will automatically be rendered after action execution if no specifying the render method invocation (like in the sample you've given)
The third option is to specify the model map:
def myAction() {
...
[param1key: param1value, param2key: param2value, ...]
}
The model will be taken into account when rendering your gsp view.
Please read the documentation I gave link to. It's incredibly helpful.

MVC identity changing user roles

I have a Vb.net MVC project with single user authentication. Admins can view all users within a "manager users" page, users are split in to 3 different roles Admin, Employee and User respectively. I want Admins to be able to promote roles: Users to Employee or Employee to Admin, and also demote.
I thought about adding a button next to each user to either promote or demote. I'm struggling as to how each button would be linked to each user and how i would post that one user change back to the controller.
Could someone please advise, thanks
UserViewModels.vb
Public Class GroupedUserViewModel
Public Property Users() As List(Of UserViewModel)
Public Property Admins() As List(Of UserViewModel)
Public Property Employee() As List(Of UserViewModel)
End Class
Public Class UserViewModel
Public Property FullName() As String
Public Property Email() As String
Public Property RoleName() As String
End Class
View:
I'm displaying all Admin, Employee and User roles within the view, here is the admin example:
#Modeltype GroupedUserViewModel
#If Model.Admins.Any Then
#:<div Class="Rtable Rtable--3cols Rtable--collapse">
#For Each Admin In Model.Admins
#:<div Class="Rtable-cell">
#Admin.FullName
#:</div>
#:<div Class="Rtable-cell">
#Admin.Email
#:</div>
#:<div Class="Rtable-cell">
#Admin.RoleName
#:</div>
Next Admin
#:</div>
End If
I'm going to stick with a mostly HTML-based answer, as my VB is rusty. Feel free to substitute the appropriate HTML/URL helpers or whatever you would like.
Basically, you can take one of two approaches:
Have a separate form for each button. This makes the most sense if you also have separate actions for each button (i.e. you have a Promote action and a Demote action on your controller.
<form action="/path/to/promote/action" method="post">
<input type="hidden" name="userId" value="1" />
<button type="submit">Promote</button>
</form>
<form action="/path/to/demote/action" method="post">
<input type="hidden" name="userId" value="1" />
<button type="submit">Demote</button>
</form>
One form with both "Promote" and "Demote" buttons. This obviously makes more sense if you have just one action that will handle both processes.
<form action="/path/to/role/change/action" method="post">
<input type="hidden" name="userId" value="1" />
<button type="submit" name="promote">Promote</button>
<button type="submit" name="demote">Demote</button>
</form>
Then, since only the button that is clicked will be included in the post data, you can branch in your action accordingly:
If Request.Form["promote"] IsNot Nothing Then
'promote user
ElseIf Request.Form["demote"] IsNot Nothing Then
'demote user
EndIf
You could also get fancier and use AJAX to handle this, but this should be enough to get you going.

Grails where is the instance updated between "create" and "save"

I'm wondering, in the scaffold controller and views, how the fields you fill in the "create" page get updated to your domain class instance before the save action. I'm on Grails 2.4.4.
Take an example, I have one class called Customer and I generate the controller and views all in the default way.
class Customer {
String name;
String email;
String address;
String mobile;
}
And when you run the application and in the generated green-styled index page, click on "create new customer", one Customer instance will be created as the link goes to "create" action.
<ul>
<li><a class="home" href="${createLink(uri: '/')}"><g:message code="default.home.label"/></a></li>
<li><g:link class="create" action="create"><g:message code="default.new.label" args="[entityName]" /></g:link></li>
</ul>
In controller:
def create() {
log.info "A customer object is created here.";
Customer c=new Customer(params)
respond c
}
But now you haven't filled in the form on all the fields yet! And after you fill in the form in create.gsp, the link will point you directly to "save" action.
<g:form url="[resource:customerInstance, action:'save']" >
<fieldset class="form">
<g:render template="form"/>
</fieldset>
<fieldset class="buttons">
<g:submitButton name="create" class="save" value="${message(code: 'default.button.create.label', default: 'Create')}" />
</fieldset>
</g:form>
But in the save action I see nothing related to setting the fields on this instance as the form goes. Where is it done?
#Transactional
def save(Customer customerInstance) {
if (customerInstance == null) {
notFound()
return
}
if (customerInstance.hasErrors()) {
respond customerInstance.errors, view:'create'
return
}
customerInstance.save flush:true
//omit everything after save here
}
Grails does this for you automatically with Data Binding. Grails controllers can take two categories of arguments: basic objects, and complex objects. The default behavior is to map HTTP request parameters to action arguments by name, wherever applicable. For example, say we have a controller like so:
def doSomething(Integer magicNumber) {
println "The magic number is $magicNumber"
}
and a view that contains a field like this:
<g:textField name="magicNumber" value="${magicNumber}" />
When the form is submitted to the doSomething action, Grails will automatically take the magicNumber request param, convert it from a String to an Integer and pass it to the action.
Complex types (like domain objects) are treated as command objects. Command objects function in a similar manner to basic objects in regards to data binding. Notice how in your code, the save action takes a Customer instance as an argument? Behind the scenes, Grails takes the HTTP request parameters and binds those parameters to the properties of a given object, in this case, a Customer. From the documentation:
Before the controller action is executed Grails will automatically create an instance of the command object class and populate its properties by binding the request parameters.
In other words, Grails will look at all of the incoming request parameters and attempt to bind those to properties on the object that you've stated as an argument to the action. In addition, it will perform validation for you. It's essentially the same as:
#Transactional
def save() {
Customer customerInstance = new Customer(params)
customerInstance.validate()
if (customerInstance == null) {
notFound()
return
}
if (customerInstance.hasErrors()) {
respond customerInstance.errors, view:'create'
return
}
customerInstance.save flush:true
//omit everything after save here
}

params values are always null in controller on clicking <g:actionSubmit> button

In my application, I have search button and based on the search criteria, I have to search data. I have used few hidden variables to store data.
My .gsp page looks like this:
<g:form id="job" name="job" method="POST">
<div>
<input type="hidden" id="country" name="country" value="${country}"/>
<input type="hidden" id="paginationFlag" name="paginationFlag" value="${paginationFlag}"/>
<!-- There are other components like text field, select box etc -->
<g:actionSubmit id="Search" value="Search" formmethod="post" action="findJob"/>
</div>
</g:form>
My respective controller method looks like this:
def findJob(){
def country
def paginationFlag
if(params?.country){
country = params?.country
}else{
country = 'USA'
}
if(params?.paginationFlag){
paginationFlag = params?.paginationFlag
}else{
paginationFlag = 'false'
}
withFormat{
html{
List<Applicant> searchList //get data from database.
// other business logic
render(view : "jobList",model:[paginationFlag: paginationFlag, country:country])
}
json{
// some business logic
def candidateList // value for this candidateList is acquired from database
def json = ['jsn': candidateList]
render json as JSON
}
}
When I click search button and debug the code, first my control goes to controller-> findJob() method and executes the code inside html part.
Secondly, it goes to the gsp page (view page) and sets value.Third, it again goes to the controller and executes the code inside json part.
On the first entry to the controller, the value of paginationFlag and country in param are both null. So it will set the value 'false' and 'USA' respectively. But when control goes to controller again for the second time, again the value of param.paginationFlag and params.country are null. Should not they have the assigned values?
Why is it so? What should I do go get the value of country and paginationFlag in params on the second time? Can any one explain me ? Thank you very much for advance.
The problem is you're using a regular HTML input tag rather than a Grails g:hiddenField tag. Try this:
<g:form id="job" name="job" method="POST">
<div>
<g:hiddenField name="country" value="${country}"/>
<g:hiddenField name="paginationFlag" value="${paginationFlag}"/>
<!-- There are other components like text field, select box etc -->
<g:actionSubmit id="Search" value="Search" formmethod="post" action="findJob"/>
</div>
</g:form>
Tip
You can also simply the params assignment:
def country = params.country ?: 'USA'
def paginationFlag = params.paginationFlag ?: 'false'
I can't tell where the paginationFlag comes from, but know that a boolean is valid.

Updating many instances in one view

I'm starting with Grails and I don't know how should I face the following use case.
The app is about sports results prediction, so I have in my domain "Match" and "Prediction", and I want to have one view where the user can update all the predictions of matches that haven't been played yet.
So far I've defined a method in my "PredictionController" that searches all the already existing predictions of games that have to be played and generates new Prediction instances for any new Match with a date higher than now. I've created a view for that method and I'm getting correctly all the predictions that I should complete or update, and I've defined in my controller another method for the form sumbission (so I'm trying to resolve this in the same way that the 'create' and 'update' scaffolded methods work).
My question is, How can I access to all the Predictions modified by my view? How can I send all the predictions to my update method? Is it defining a hidden field with a variable containing all the collection?
This is the form in my GSP view:
<g:form action="savePredicctions">
<fieldset>
<g:each in="${predictions}">
<li>
<div>
${it.match.homeTeam}
<g:field name="${it.match}.homeGoals" type="number" value="${it.homeGoals}" />
</div>
-
<div>
<g:field name="${it.match}.awayGoals" type="number" value="${it.awayGoals}" />
${it.match.awayTeam}
</div>
</li>
</g:each>
</fieldset>
<fieldset class="submit">
<g:submitButton />
</fieldset>
</g:form>
You can use a command object to store the instances of Prediction.
#Validateable
class PredictionCommand {
//data binding needs a non-null attribute, so we use ListUtils.lazyList
List<Prediction> predictions = ListUtils.lazyList([], FactoryUtils.instantiateFactory(Prediction))
}
In your view, you need to control the index of your list, and send the attributes of Prediction to the controller:
<g:each in="${predictions}" status="i">
<g:textField name="predictions[$i].homeGoals" />
<g:textField name="predictions[$i].awayGoals" />
</g:each>
And in your controller you can use bindData() to bind params to your command:
class CommandController {
def save() {
PredictionCommand command = new PredictionCommand()
bindData(command, params)
println command.predictions
}
}

Resources