grails saving object with hasmany relation through form - grails

I'm trying to create simple form for saving post with it's relations.
Here is my domain models;
Post Model;
class Post {
String title
String teaser
String content
static belongsTo = [author: Person, category: Category]
static hasMany = [tags: Tag]
static constraints = {
}
}
Tag Model;
class Tag {
String name
static belongsTo = Post
static hasMany = [posts: Post]
static constraints = {
}
}
I've created a form for saving post object through html form;
<g:form controller="posts" action="save" method="post">
<div class="input">
<label for="post.title">Title:</label>
<g:textField name="post.title" />
</div>
<div class="input">
<label for="post.teaser">Teaser:</label>
<g:textField name="post.teaser" />
</div>
<div class="input">
<label for="post.content">Content:</label>
<g:textArea name="post.content" />
</div>
<div class="input">
<label for="post.content">Category:</label>
<g:select optionKey="id" optionValue="name" name="post.category" from="${categories}" noSelection="['':'-Choose Category-']"/>
</div>
<div class="input">
<label for="post.tags">Tags:</label>
<g:select optionKey="id" optionValue="name" name="post.tags" from="${tags}" noSelection="['':'-Choose Tags-']" />
</div>
<div class="input">
<g:submitButton name="Create" value="Create" />
</div>
</g:form>
And here is the controller logic;
def save() {
def post = new Post(params.post)
post.author = springSecurityService.currentUser
if(post.save()){
flash.message = "Post created successfully..."
redirect(action: "index", method: "GET")
}
else{
flash.error = "Something went wrong, please check the form again!"
[tags: Tag.list(), categories: Category.list()]
render(view: "create")
}
}
With this way i can't save tags for post object.

I solved the problem with
post.save(flush: true)
here is the documentation about
gorm save

Related

Grails: Add items to list and attach it to its parent object

I have a Recipe, Ingredient and RecipeIngredient domains as below:
class Ingredient {
String title
}
class Recipe {
String title
String description
static hasMany = [ingredients: RecipeIngredient]
}
class RecipeIngredient {
Ingredient ingredient
static belongsTo = [recipe: Recipe]
Measure measure
Double amount
}
In my recipe/Create.gsp page when I want to create a new recipe, I want to add its ingredients one by one and addto recipe instance and save them all together.
<g:form controller="recipe" action="save" method="POST">
**/* HERE I WANT TO BE ABLE TO ADD ALL INGREDIENTS ONE BY ONE */
<select value="${recipe_ingredient.ingredient}">
<g:each in="${allIngredients}" status="i" var="ingredient">
<option>${ingredient.title}</option>
</g:each>
</select>
<select name="recipe_ingredient.measure" value="${recipe_ingredient.measure}">
<g:each in="${enums.Measure.values()}" var="m">
<option>${m}</option>
</g:each>
</select>
<input name="recipe_ingredient.amount" placeholder="Measure" value="${recipe_ingredient.amount}" />
<g:actionSubmit value="Add" action="addIngredient" />
/* END */**
<div class="row">
<input name="title" value="${instance?.title}" placeholder="Title" />
</div>
<div class="row">
<input name="titleEng" value="${instance?.description}" placeholder="Description" />
</div>
<div class="row">
<g:submitButton name="Create" />
</div>
</g:form>
How can I achieve such thing?
The straight-forward way would be:
<g:select name="rawIngredients" value="${recipe.ingredients*.ingredient*.id}"
from="${allIngredients}" optionKey="id" optionValue="title" multiple="true"/>
Then in the controller:
def save() {
Recipe recipe // bind or create somehow, e.g. via command-object
recipe.ingredients?.clear()
Ingredient.getAll( params.list( 'rawIngredients' ) ).each{ ing ->
recipe.addToIngredients new RecipeIngredient( ingredient:ing, amount:1, ... )
}
recipe.save()
}

g:select save to database selected item in grails

I have tables: Products and Shop.(I generate controllers using grails generate-all) Shop hasmany products
I'm trying to do is List all the shops in and save to database selected shop when creating a new product.
I listed all values using
<g:form controller="product" action="save" role="form">
<div class="form-horizontal" role="form">
<div class="form-group">
<label class="col-lg-3 control-label">Product Name:</label>
<div class="col-lg-8">
<g:textField name="productName" class="form-control" value="${product.productName}"/>
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Product Barcode</label>
<div class="col-lg-8">
<g:textField name="date expired" class="form-control" value="${product.productBarcode}"></g:textField>
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Product Shop</label>
<g:select class="selectpicker" name="products.id" from="${tr.com.netiket.lkkstoreapp.Shop.list()}" value="shop?.products.id" optionValue="shopName"></g:select>
</div>
</g:form>
when i click create button it says
Property [shop] of class [class tr.com.nur.storeapp.Product] cannot be null
This bit doesn't look right:
<g:select class="selectpicker" name="products.id" from="${tr.com.netiket.lkkstoreapp.Shop.list()}" value="shop?.products.id" optionValue="shopName"></g:select>
The name should be the id of the Shop and the value should be the product's shop id, if present:
<g:select class="selectpicker" name="shop.id" from="${tr.com.netiket.lkkstoreapp.Shop.list()}" value="${product?.shop?.id}" optionValue="shopName"></g:select>
#Transactional
def save(Shop shop) {
//println "in shop save"
def currentUser=(User)springSecurityService.currentUser
shop.user=currentUser
shop.validate()
if (!shop) {
//println "I have no shop"
transactionStatus.setRollbackOnly()
notFound()
return
}
//if (shop.hasErrors()) {
if (shop.save(flush:true)) {
//println "shop has errors"
transactionStatus.setRollbackOnly()
respond shop.errors, view:'create'
shop.errors.allErrors
return
}
//shop.save flush:true
//println "shop has saved"
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.created.message', args: [message(code: 'shop.label', default: 'Shop'), shop.id])
//println "redirecting"
redirect shop
}
'*' { respond shop, [status: CREATED] }
}
}
This is my save method. Actuaally I didint write anything here. Generate domain .

groovy.lang.MissingMethodException new1.EmployeeController.findByUsername()

I was trying to make a signup page, which takes the username and password as from the user and stores it in my database, but the problem here is, the data is not going to the database only
you can see the image here
[https://drive.google.com/file/d/0B9gjSzsLSnClR1VvU0RUa3liRWs/view?usp=sharing][1]
save method look likes this
#Transactional
def save(){
if(params == null){
redirect(action:"index")
flash.message=''
return
}
def employee = findByUsername(params.username);
System.out.println(employee.username);
if(employee!=null){
flash.message="username already exist"
render(view:"signup")
}
else{
def newEmp = new Employee();
newEmp.username=params.username
newEmp.password=params.password
if(newEmp.save(flush:true)){
flash.message="Employee created"
render(view:"index")
}
else{
flash.message="Please enter valid data"
render(view:"signup")
}
if(newEmp.save(flush:true)) {
flash.message = "User Created. Please Login"
render(view:"index")
} else {
flash.message = "Please enter valid data";
render(view:"signup")
}
}
}
View page look like this
<form id="signupform" action="./save" method="POST" class="form-horizontal" role="form">
<g:if test="${flash.message}">
<div class="alert alert-danger" role="alert">${flash.message}</div>
</g:if>
<div class="form-group">
<label for="username" class="col-md-3 control-label">Username</label>
<div class="col-md-9">
<input type="text" class="form-control" name="username" placeholder="Username">
</div>
</div>
<div class="form-group">
<label for="password" class="col-md-3 control-label">Password</label>
<div class="col-md-9">
<input type="password" class="form-control" name="password" placeholder="Password">
</div>
</div>
<div class="form-group">
<!-- Button -->
<div class="col-md-offset-3 col-md-9 text-center">
<button id="btn-signup" type="submit" class="btn btn-info"><i class="icon-hand-right"></i>Sign Up</button>
</div>
</div>
</form>
Replace this:
def employee = findByUsername(params.username);
with:
def employee = Employee.findByUsername(params.username);
All dynamic finder methods must be called statically on the type you expect them to return

MVC Razor, How to keep Model object between Actions

I'm trying to display a product stock list.
I would like to let the user an option to edit the quantity's and the ability to remove a product from this list. the problem is, the Model object disappear after the submit action. i would like to preserve it, in order to update the stock in DB later on.
Controllers:
public ActionResult EditProducts()
{
//! Pulling DATA from db using DbContext
ProductDAL proDAL = new ProductDAL();
List<Products> pl = proDAL.Products.ToList<Products>();
ProductModel productModel = new ProductModel();
productModel.oneProduct = new Products();
productModel.ProductsCollection = new List<Products>();
productModel.ProductsCollection = pl;
TempData["pM"] = productModel;
return View("EditProducts", TempData["pM"]);
}
public ActionResult SubmitProductsValues(ProductModel productModel)
{
//! Some farther work to do...
return View("EditProducts", TempData["pM"]);
}
My View:
#using (Html.BeginForm("SubmitProductsValues", "Admin", FormMethod.Post))
{
<div class="col-xs-12 hclearfix edit">
<div class="col-xs-2 eRow et"><b>Product SKU</b></div>
<div class="col-xs-2 eRow et"><b>Product Name</b></div>
<div class="col-xs-2 eRow et"><b>Product Price</b></div>
<div class="col-xs-2 eRow et"><b>Product Quantity</b></div>
<div class="col-xs-2 eRow et"><b>Product Picture</b></div>
<div class="col-xs-1 eRow et"><b>pId</b></div>
<div class="col-xs-1 eRow et"><b>Remove?</b></div>
#{ int i = 0; }
#foreach (Products obj in Model.ProductsCollection)
{
<div class="col-xs-2 eRow">#Html.Raw(obj.SKU)</div>
<div class="col-xs-2 eRow">#Html.Raw(obj.Name)</div>
<div class="col-xs-2 eRow">#Html.Raw(obj.Price)</div>
<div class="col-xs-2 eRow">#Html.EditorFor(m=>m.ProductsCollection[i].Quantity)</div>
<div class="col-xs-2 eRow">#Html.Raw(obj.PicURL)</div>
<div class="col-xs-1 eRow">#Html.Raw(obj.Id)</div>
<div class="col-xs-1 eRow">#Html.CheckBox("remove")</div>
i++;
}
<div class="col-xs-12 eRow">
<p class="left">
<input type="submit" id="btnSubmit" value="Save Changes" />
</p>
<p class="alert-danger right">
#Html.ValidationSummary()
</p>
</div>
</div>
BTW, only this raw: #Html.EditorFor keeps the values of the returned data.
but i would like to avoid using #Html.EditorFor for the other fields, while
keeping those fields data.
Thank you so much for your help (:
You are getting null because the other field values are not in the form fields. Model binding will map the data from your form fields ( with names matching to your view model property name). Currently you are displaying Name, Price etc in just a div, not an input field.
But since you do not want to update any other fields, you should not worry about getting other field value as null. What you need is the unique Id of your record and the Quantity field value which has the updated value from form.
Als you do not need TempData. You can pass your model to the View method.
public ActionResult EditProducts()
{
var proDAL = new ProductDAL();
List<Products> pl = proDAL.Products.ToList<Products>();
ProductModel productModel = new ProductModel();
productModel.ProductsCollection = new List<Products>();
productModel.ProductsCollection = pl;
return View("EditProducts",productModel);
}
And in your view, you need to create input fields with names which matches the property name so that model binding will work when you post the form.
#model ProductModel
#using (Html.BeginForm("SubmitProductsValues", "Admin", FormMethod.Post))
{
<h2>Items</h2>
int i = 0;
foreach(var p in Model.Products)
{
<div>#p.Name</div>
<input type="hidden" name="ProductsCollection[#i].Id" value="#p.Id" />
<input type="text" name="ProductsCollection[#i].Quantity" value="#p.Quantity" />
}
<input type="submit" value="Update" />
}
Now in your HttpPost, you will have the ProductsCollection available withe updated data from the form user submitted.
[HttpPost]
public ActionResult SubmitProductsValues(ProductModel model)
{
// loop through model.ProductsCollection
foreach(var p in Model.ProductsCollection)
{
var q=p.Quantity;
var id=q.Id;
// to do : update quantity of the record for the value in Id variable.
}
// to do : Save and redirect
}
<input type="hidden" name="ProductsCollection[#i].SKU" value="#p.SKU" />
<input type="hidden" name="ProductsCollection[#i].Name" value="#p.Name" />
<input type="hidden" name="ProductsCollection[#i].Price" value="#p.Price" />
<input type="hidden" name="ProductsCollection[#i].PicURL" value="#p.PicURL" />
<input type="hidden" name="ProductsCollection[#i].Id" value="#p.Id" />
Thanks to #Shyju (:

Grails databinding multiple domain classes

HI. I have this classes:
class Carro {
String name
String marca
String matricula
static constraints = {
name(nullable:false, blank:false)
}
static mapping = {
version false
}
}
class CarroMovel {
String move
String rodas
String espelhos
Carro carro
static hasMany = [carros: Carro]
static constraints = {
move(nullable:false, blank:false)
}
static mapping = {
version false
}
}
And the controllers:
class CarroController{
def save2 = {
def carroInstance = new Carro()
carroInstance.name = params.name
carroInstance.marca = params.marca
carroInstance.matricula = params.matricula
if (carroInstance.save(flush: true)) {
redirect(uri:"/home.gsp")
}
else {
render(view: "/testeAdd", model: [carroInstance: carroInstance])
}
}
And the view testeAdd.gsp
<g:form controller="carro" action="save2">
<h1>Add New Carro Record</h1>
<p>Basic Information</p>
<label>Name
<span class="small">as</span>
</label>
<input type="text" name="name" value="${carroInstance?.name}" /><br>
<label>Marca
<span class="small">as</span>
</label>
<input type="text" name="marca" value="${carroInstance?.marca}" /><br
<label>Matricula
<span class="small">as</span>
</label>
<input type="text" name="matricula" value="${carroInstance?.matricula}" /><br>
<g:submitButton name="save" value="Save" id="oneone"/>
<div class="spacer"></div>
</g:form>
<g:hasErrors bean="${carroInstance}">
<div class="errors">
<g:renderErrors bean="${carroInstance}" as="list" />
</div>
</g:hasErrors>
This is working good. Now i would like to be able to data binding multiple domain classes. So, along with the current code from my gsp file, i would also like to add carroMovel occurrences all in same save2. Im not sure how to do that, specially cause class Carro will need to have an id from class carroMovel. Any help please? Thank you.
I folowed some suggestions and now the results are as follows (im not concerned about error validation yet):
def save3 = {
def carroInstance = new Carro()
def carroMovelInstance = new CarroMovel()
carroInstance.name = params.carro.name
carroInstance.marca = params.carro.marca
carroInstance.matricula = params.carro.matricula
carroMovelInstance.move = params.carroMovel.move
carroMovelInstance.rodas = params.carroMovel.rodas
carroMovelInstance.espelhos = params.carroMovel.espelhos
carroInstance.save()
carroMovelInstance.carro = carroInstance
carroMovelInstance.save()
}
<g:form controller="carro" action="save3">
<h1>Add New Conference Record</h1>
<p>Basic Information</p>
<label>Name
<span class="small">Add your name</span>
</label>
<input type="text" name="carro.name" value="${carroInstance?.name}" /><br>
<label>Marca
<span class="small">Add your name</span>
</label>
<input type="text" name="carro.marca" value="${carroInstance?.marca}" /><br
<label>Matricula
<span class="small">Add your name</span>
</label>
<input type="text" name="carro.matricula" value="${carroInstance?.matricula}" /><br>
<label>Move
<span class="small">Add your name</span>
</label>
<input type="text" name="carroMovel.move" value="${carroMovelInstance?.move}" /><br>
<label>Rodas
<span class="small">Add your name</span>
</label>
<input type="text" name="carroMovel.rodas" value="${carroMovelInstance?.rodas}" /><br>
<label>Espelho
<span class="small">Add your name</span>
</label>
<input type="text" name="carroMovel.espelho" value="${carroMovelInstance?.espelho}" /><br>
<g:submitButton name="save" value="Save" id="addConference"/>
The Carro object is saved in the database, altought, nothing happens with CarroMovel and it is not saved and i can't figure it out.
First I would change the input names to carro.name, carro.marca, carroMovel.move, ... so that they are differentiated by name.
<input type="text" name="carro.name"/><br>
<input type="text" name="carro.marca"/><br>
<input type="text" name="carroMovel.move"/><br>
This has the advantage that the binding in the controller can be done the standard Grails way, and that the correct values are entered in the form without the value attribute set.
carro.properties = params.carro
carroMovel.properties = params.carroMovel
In the controller action you can also save and link the Carro and CarroMovel instances.
carro.save()
carroMovel.carro = carro
carroMovel.save()
if(carroMovel.hasErrors(){
render(view: 'save3', model: [carro: carro, carroMovel.carroMovel])
}
If I understand your question correctly, you can give this a try.
First, edit our form to include the necessary fields for the CarroMovel class,
e.g
<label>Move
<span class="small">as</span>
</label>
<input type="text" name="move" value="${carroMovelInstance?.move}" />
then
in your save2 action,
def carroInstance = new Carro()
carroInstance.name = params.name
carroInstance.marca = params.marca
carroInstance.matricula = params.matricula
def carroMovelInstance = new CarroMovel()
carroMovelInstance.name = params.move
carroMovelInstance.marca = params.rodasa
carroMovelInstance.matricula = params.espelhos
carroMovelInstance.carro = carroInstance
Since Carro does not belong to CarroMovel saving a carroMovelInstance will not cascade to the carroInstance, therefore you will need to save each instance individually before saving its owning instance.
carroMovelInstance.carro.save()
if (carroMovelInstance.save(flush: true)) {
redirect(uri:"/home.gsp")
}
else {
render(view: "/testeAdd", model: [carroInstance: carroInstance, carroMovelInstance:carroMovelInstance])
}
Let me know if that works out for you.
Some of the other answers may be simpler, but I've been using this technique:
http://omarello.com/2010/08/grails-one-to-many-dynamic-forms/
In order for Carro to cascade save the CarroMovel reference, CarroMovel needs belongsTo = Carro or you need to manually tell hibernate to cascade it upon save using something like this:
class CarroMovel{
static mapping = {
carro cascade: 'all'
}
}
Here's the hibernate documentation about cascading:
https://docs.jboss.org/hibernate/orm/4.0/javadocs/org/hibernate/metamodel/binding/CascadeType.html
I usually use a command object for this type of thing.
In your controller do something like this:
class CarroController {
def show = {
[cmd: new MyCommand()]
}
def save2 = { MyCommand cmd ->
def carro = cmd.carro
if (carro.save()) {
cmd.movel.carro = carro
if (cmd.movel.save()) {
redirect uri: 'home.gsp'
} else {
// show form again
render view: 'show', model:[cmd:cmd]
}
} else {
// show form again
render view: 'show', model:[cmd:cmd]
}
}
// same file or some other class file
class MyCommand {
Carro carro
CarroMovel movel
}
}
You will need to adjust your form a bit as well...
Where you have "Carro" fields reference them like this:
<input type="text" name="carro.matricula" value="${cmd.carro?.matricula}" />
Where you have the "CarroMovel" fields, like this:
<input type="text" name="movel.rodas" value="${cmd.movel?.rodas}" />
This code might not be exactly right (I didn't test it), but should get you down the correct path. Also instead of referencing the objects in the command object, you could just have the fields that you are binding, and then build the actual domain objects from them, either through a helper method (def buildCarro(){...}) or by hand in the controller method.

Resources