title: Passing parameters to a form grails
body: <p>I am new to grails I am trying to pass an object Id to a form. I have domains called Beer and recipe. Beer hasMany recipes and recipe belongsTo beer. I want to create a link to a new recipe from the beer show page passing the beer id in the url in order to create the association. Right now I have been trying to use this link <code>&lt;g:link controller="recpie" action="create" params="[beerid: selectedBeer.id]"&gt;Create Recipe&lt;/g:link&gt;</code> and retrieve it in the form as a hidden field to submit with the recipe form using <code>&lt;g:field type="text" name="beer.id" value="${beer}"/&gt;.</code>(I know that the hidden property is not set). What am I doing wrong? Also is there a better way to create this association? </p>
  
  <p><strong>Beer Domain Class</strong></p>
  
  <pre><code>class Beer {
  
      String name
      String style
      Recipe recipe
  
      String toString() {
          name
      }
  
      static hasMany = [recipe : Recipe]
  
  
      static constraints = {
      }
  }
  </code></pre>
  
  <p><strong>Recipe Domain Class</strong></p>
  
  <pre><code>class Recipe {
  
      String name
      Float grainAmount
      String yeast
      float boilTime
      Float hopAmount
      float og
      float fg
      float ogTemp
      float fgTemp
      float fermTime
      Beer beer
  
  
      static belongsTo = [ beer: Beer]
  
      static constraints = {
          beer nullable: true
      }
  
      String toString() {
          name
      }
   }
  </code></pre>
  
  <p><strong>Beer Controller</strong></p>
  
  <pre><code>package com.example
  
  import static org.springframework.http.HttpStatus.*
  import grails.transaction.Transactional
  
  @Transactional(readOnly = true)
  class BeerController {
  
      static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
  
      def index(Integer max) {
          params.max = Math.min(max ?: 10, 100)
          respond Beer.list(params), model:[beerCount: Beer.count()]
      }
  
      def show(Beer beer) {
  
          respond beer
      }
  
      def create() {
          respond new Beer(params)
      }
  
      @Transactional
      def save(Beer beer) {
          if (beer == null) {
              transactionStatus.setRollbackOnly()
              notFound()
              return
          }
  
          if (beer.hasErrors()) {
              transactionStatus.setRollbackOnly()
              respond beer.errors, view:'create'
              return
          }
  
          beer.save flush:true
  
          request.withFormat {
              form multipartForm {
                  flash.message = message(code: 'default.created.message', args: [message(code: 'beer.label', default: 'Beer'), beer.id])
                  redirect beer
              }
              '*' { respond beer, [status: CREATED] }
          }
      }
  
      def edit(Beer beer) {
          respond beer
      }
  
      @Transactional
      def update(Beer beer) {
          if (beer == null) {
              transactionStatus.setRollbackOnly()
              notFound()
              return
          }
  
          if (beer.hasErrors()) {
              transactionStatus.setRollbackOnly()
              respond beer.errors, view:'edit'
              return
          }
  
          beer.save flush:true
  
          request.withFormat {
              form multipartForm {
                  flash.message = message(code: 'default.updated.message', args: [message(code: 'beer.label', default: 'Beer'), beer.id])
                  redirect beer
              }
              '*'{ respond beer, [status: OK] }
          }
      }
  
      @Transactional
      def delete(Beer beer) {
  
          if (beer == null) {
              transactionStatus.setRollbackOnly()
              notFound()
              return
          }
  
          beer.delete flush:true
  
          request.withFormat {
              form multipartForm {
                  flash.message = message(code: 'default.deleted.message', args: [message(code: 'beer.label', default: 'Beer'), beer.id])
                  redirect action:"index", method:"GET"
              }
              '*'{ render status: NO_CONTENT }
          }
      }
  
      protected void notFound() {
          request.withFormat {
              form multipartForm {
                  flash.message = message(code: 'default.not.found.message', args: [message(code: 'beer.label', default: 'Beer'), params.id])
                  redirect action: "index", method: "GET"
              }
              '*'{ render status: NOT_FOUND }
          }
      }
  }
  </code></pre>
  
  <p><strong>Recipe Controller</strong></p>
  
  <pre><code>package com.example
  
  import static org.springframework.http.HttpStatus.*
  import grails.transaction.Transactional
  
  @Transactional(readOnly = true)
  class RecipeController {
  
      static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
  
      def index(Integer max) {
          params.max = Math.min(max ?: 10, 100)
          respond Recipe.list(params), model:[recipeCount: Recipe.count()]
      }
  
      def show(Recipe recipe) {
          respond recipe
      }
  
      def create() {
          respond new Recipe(params)
      }
  
      @Transactional
      def save(Recipe recipe) {
          if (recipe == null) {
              transactionStatus.setRollbackOnly()
              notFound()
              return
          }
  
          if (recipe.hasErrors()) {
              transactionStatus.setRollbackOnly()
              respond recipe.errors, view:'create'
              return
          }
  
          recipe.save flush:true
  
          request.withFormat {
              form multipartForm {
                  flash.message = message(code: 'default.created.message', args: [message(code: 'recipe.label', default: 'Recipe'), recipe.id])
                  redirect recipe
              }
              '*' { respond recipe, [status: CREATED] }
          }
      }
  
      def edit(Recipe recipe) {
          respond recipe
      }
  
      @Transactional
      def update(Recipe recipe) {
          if (recipe == null) {
              transactionStatus.setRollbackOnly()
              notFound()
              return
          }
  
          if (recipe.hasErrors()) {
              transactionStatus.setRollbackOnly()
              respond recipe.errors, view:'edit'
              return
          }
  
          recipe.save flush:true
  
          request.withFormat {
              form multipartForm {
                  flash.message = message(code: 'default.updated.message', args: [message(code: 'recipe.label', default: 'Recipe'), recipe.id])
                  redirect recipe
              }
              '*'{ respond recipe, [status: OK] }
          }
      }
  
      @Transactional
      def delete(Recipe recipe) {
  
          if (recipe == null) {
              transactionStatus.setRollbackOnly()
              notFound()
              return
          }
  
          recipe.delete flush:true
  
          request.withFormat {
              form multipartForm {
                  flash.message = message(code: 'default.deleted.message', args: [message(code: 'recipe.label', default: 'Recipe'), recipe.id])
                  redirect action:"index", method:"GET"
              }
              '*'{ render status: NO_CONTENT }
          }
      }
  
      protected void notFound() {
          request.withFormat {
              form multipartForm {
                  flash.message = message(code: 'default.not.found.message', args: [message(code: 'recipe.label', default: 'Recipe'), params.id])
                  redirect action: "index", method: "GET"
              }
              '*'{ render status: NOT_FOUND }
          }
      }
  }
  </code></pre>
  
  <p><strong>Beer/Show GSP</strong></p>
  
  <pre><code>    &lt;!DOCTYPE html&gt;
      &lt;html&gt;
          &lt;head&gt;
              &lt;meta name="layout" content="main" /&gt;
              &lt;g:set var="entityName" value="${message(code: 'beer.label', default: 'Beer')}" /&gt;
              &lt;title&gt;&lt;g:message code="default.show.label" args="[entityName]" /&gt;&lt;/title&gt;
          &lt;/head&gt;
          &lt;body&gt;
              &lt;a href="#show-beer" class="skip" tabindex="-1"&gt;&lt;g:message code="default.link.skip.label" default="Skip to content&amp;hellip;"/&gt;&lt;/a&gt;
              &lt;div class="nav" role="navigation"&gt;
                  &lt;ul&gt;
                      &lt;li&gt;&lt;a class="home" href="${createLink(uri: '/')}"&gt;&lt;g:message code="default.home.label"/&gt;&lt;/a&gt;&lt;/li&gt;
                      &lt;li&gt;&lt;g:link class="list" action="index"&gt;&lt;g:message code="default.list.label" args="[entityName]" /&gt;&lt;/g:link&gt;&lt;/li&gt;
                      &lt;li&gt;&lt;g:link class="list" action="create" resource="recipe"&gt;New Recipe&lt;/g:link&gt;&lt;/li&gt;
                  &lt;/ul&gt;
              &lt;/div&gt;
              &lt;div id="show-beer" class="content scaffold-show" role="main"&gt;
                  &lt;h1&gt;&lt;g:message code="default.show.label" args="[entityName]" /&gt;&lt;/h1&gt;
                  &lt;g:if test="${flash.message}"&gt;
                  &lt;div class="message" role="status"&gt;${flash.message}&lt;/div&gt;
                  &lt;/g:if&gt;
                  &lt;g:link controller="recpie" action="create" resource="recipe" params="[beerid: selectedBeer.id]"&gt;Create Recipe&lt;/g:link&gt;
                  &lt;f:display bean="beer" /&gt;
                  &lt;g:form resource="${this.beer}" method="DELETE"&gt;
                      &lt;fieldset class="buttons"&gt;
                          &lt;g:link class="edit" action="edit" resource="${this.beer}"&gt;&lt;g:message code="default.button.edit.label" default="Edit" /&gt;&lt;/g:link&gt;
                          &lt;input class="delete" type="submit" value="${message(code: 'default.button.delete.label', default: 'Delete')}" onclick="return confirm('${message(code: 'default.button.delete.confirm.message', default: 'Are you sure?')}');" /&gt;
                      &lt;/fieldset&gt;
                  &lt;/g:form&gt;
              &lt;/div&gt;
          &lt;/body&gt;
      &lt;/html&gt;
  </code></pre>
  
  <p>** Recipe/Create GSP**</p>
  
  <pre><code>&lt;%@ page import="com.example.Beer" %&gt;
  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
      &lt;head&gt;
          &lt;meta name="layout" content="main" /&gt;
          &lt;g:set var="entityName" value="${message(code: 'recipe.label', default: 'Recipe')}" /&gt;
          &lt;title&gt;&lt;g:message code="default.create.label" args="[entityName]" /&gt;&lt;/title&gt;
      &lt;/head&gt;
      &lt;body&gt;
          &lt;a href="#create-recipe" class="skip" tabindex="-1"&gt;&lt;g:message code="default.link.skip.label" default="Skip to content&amp;hellip;"/&gt;&lt;/a&gt;
          &lt;div class="nav" role="navigation"&gt;
              &lt;ul&gt;
                  &lt;li&gt;&lt;a class="home" href="${createLink(uri: '/')}"&gt;&lt;g:message code="default.home.label"/&gt;&lt;/a&gt;&lt;/li&gt;
                  &lt;li&gt;&lt;g:link class="list" action="index"&gt;&lt;g:message code="default.list.label" args="[entityName]" /&gt;&lt;/g:link&gt;&lt;/li&gt;
              &lt;/ul&gt;
          &lt;/div&gt;
          &lt;div id="create-recipe" class="content scaffold-create" role="main"&gt;
              &lt;h1&gt;&lt;g:message code="default.create.label" args="[entityName]" /&gt;&lt;/h1&gt;
              &lt;g:if test="${flash.message}"&gt;
              &lt;div class="message" role="status"&gt;${flash.message}&lt;/div&gt;
              &lt;/g:if&gt;
              &lt;g:hasErrors bean="${this.recipe}"&gt;
              &lt;ul class="errors" role="alert"&gt;
                  &lt;g:eachError bean="${this.recipe}" var="error"&gt;
                  &lt;li &lt;g:if test="${error in org.springframework.validation.FieldError}"&gt;data-field-id="${error.field}"&lt;/g:if&gt;&gt;&lt;g:message error="${error}"/&gt;&lt;/li&gt;
                  &lt;/g:eachError&gt;
              &lt;/ul&gt;
              &lt;/g:hasErrors&gt;
              &lt;g:form action="save" name="recipeForm"&gt;
                  &lt;fieldset class="form"&gt;
                      Name:
                      &lt;g:field type="text" name="name"/&gt;
                      Grain Amount:
                      &lt;g:field type="text" name="grainAmount"/&gt;
                      Yeast:
                      &lt;g:field type="text" name="yeast"/&gt;
                      Boil Time:
                      &lt;g:field type="text" name="boilTime"/&gt;
                      Hop Amount:
                      &lt;g:field type="text" name="hopAmount"/&gt;
                      OG:
                      &lt;g:field type="text" name="og"/&gt;
                      FG:
                      &lt;g:field type="text" name="fg"/&gt;
                      OG Temp:
                      &lt;g:field type="text" name="ogTemp"/&gt;
                      FG Temp:
                      &lt;g:field type="text" name="fgTemp"/&gt;
                      Ferment Time:
                      &lt;g:field type="text" name="fermTime"/&gt;
                      beer:
                      &lt;g:hiddenField name="beerid" value="${params.beerid}" /&gt;
  
  
                  &lt;/fieldset&gt;
  
                  &lt;fieldset class="buttons"&gt;
                      &lt;g:submitButton name="create" class="save" value="${message(code: 'default.button.create.label', default: 'Create')}" /&gt;
                  &lt;/fieldset&gt;
              &lt;/g:form&gt;
          &lt;/div&gt;
      &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>