Contents
- Intro + Building Grails App + Domain
- Adding the Grid + Form + Image Upload
- Registration + ACL’s + Filter Data for User + Securing User Data + Updating Image Uploads to User Dir
- Edit and Delete on Posts + eMail
- Setting Up MySQL with Grails + Tomcat Config Changes + Deploying WAR to Production Environments
[divider]
Adding the Grid + Form + Image Upload
In part I, we created the grails app and defined our data model, as well as generated the controller and views necessary to do some basic CRUD. Keep in mind, if you change your data model, you can easily generate it again with generate-all [domain] and it will rebuild your controllers and views. BUT, as you start adding your own code into the controllers and views you won’t want to do that anymore… it will destroy your code. So it’s cool to generate this in the beginning but soon you’ll want to do all future updates by hand.
The Grid
We want to use a Grid. The excel like display on the user’s page. We’ll use a plugin here. Plugins are like Rails Gems (if you are familiar with Gems.) They are packages of code that perform a function, so you don’t have to write it yourself.
We’ll use Easygrid. So, do a google search for Easygrid plugin. You’ll find this page: http://grails.org/plugin/easygrid
At the top it tells you:
Dependency :
compile ":easygrid:1.4.5"
At the time of this writing, that version is the latest. If it shows a different value, use that instead. What we do is copy the compile “:easy grid:1.4.5” and paste it into the /conf/BuildConfig.groovy file – within the plugin closure.
So open up the BuildConfig.groovy file, find the plugins and you’ll see some other plugins there with compile… just put this inside the same plugin closure. Once done, compile… just a grails compile from the command line, or within Intellij you open up your console and do a compile.
In the latest easy grid, I’m told there’s a message about generating the config script. If so, run that command. If not, then you’ll need to open the /conf/EasygridConfig.groovy file and add in the config file from the author’s example github repo.
Let’s make a page for the users… we’ll call it the dashboard. So create a controller called Dashboard. You can do this in Intellij by right clicking the controller and choosing New Grails Controller. Give it the name DashboardController and hit enter.
Open the Dashboard controller-above the class definition add this annotation:
@Easygrid
and above the index() action, lets add this:
def tradingCardInventoryGrid = {
dataSourceType ‘gorm’
domainClass TradingCardInventory
gridImpl ‘jqgrid’
columns {
id {
label ‘ ‘
type ‘id’
}
description{
jqgrid {
editable false
}
label ‘Description’
….continue adding these columns that reflect your data. For reference, you can view the author’s own sample grid definition here: https://github.com/tudor-malene/Easygrid_example/blob/master/grails-app/controllers/example/AuthorController.groovy
This defines how the grid will display. By default we’ll use jqgrid’s config. It has a nice look and feel. you can leave editable on (by removing my example false tag, or turn it true. This lets you do inline editing.)
Once it’s created, open the Views folder and create a sub folder called “dashboard.” Inside the dashboard folder create a new GSP (in Intellij you do this with Right clicking the dashboard folder and do a New GSP.) Name this new GSP index.gsp So it will look like this file structure: /views/dashboard/index.gsp
Open the /views/dashboard/inxed.gsp
Above the header add this:
<%@ page import=”[your package].TradingCardInventory” %>
<%@ page import=”[your package].TradingCardInventoryController” %>
<%@ page import=”[your package].DashboardController” %>
For reference, you can see how pages are imported on the generated page /views/tradingcardinventory/index.gsp
In the header of your /views/dashboard/index.gsp add this:
<r:require modules=”easygrid-jqgrid-dev”/>
<r:layoutResources/>
You might need to have the layout resources added in the body as well.
In the body add this tag:
<grid:grid name=”tradingCardInventory” jqgrid.width=’700′ jqgrid.caption='”My Items”‘ />
Save and run your app. You should be able to go to the localhost:8080/dashboard and see your page. If you have data in your database it should render out in the grid. To add data, just go to your main controller: localhost:8080/tradingCardInventory and add some data, return to the dashboard and see if it loads with data.
Common Problems
The Grid Doesn’t Load data!: Check that you have the /conf/EasygridConfig.groovy file loaded with the default config… I’ve been told that the latest easy grid plugin (post this writing) has a way to generate this file. You can of course copy the default code from the developer’s sample site. The author originally put his easy grid config in the Config.groovy file… here’s his example: https://github.com/tudor-malene/Easygrid_example/blob/master/grails-app/conf/Config.groovy within that you’ll see a easy grid closure. If you copy that easy grid{} closure out and paste it into your /conf/EasygridConfig.groovy file it should work (ONLY Do this if you don’t have any config loaded.)
The Grid doesn’t Render Right!: Make sure you have that <r:layoutResources/> tag on the dashboard/index.gsp page. I believe I added this both to the header as well as in the body. It should only need one placement. Try either or both.
If you still have problems with Easygrid, check out the developers site for more info: https://github.com/tudor-malene/Easygrid
If the Grid is working, great! Let’s add a form for users to add data. I think it would be a shame if the user had to go to a different page to submit data. So lets put a form on this page to submit data to the database.
Adding a Form To Submit Data
To start with, lets not do the image upload just yet… that’s a bit tricky and i’ll save it for the end.
Somewhere on the page add a form like so:
<%
def tradingCardInventoryInstance = new TradingCardInventory()
%>
<g:form url=”[resource:tradingCardInventoryInstance, action: ‘save'”>
<g:textField name=”description” maxLength=”90″ size=”20″ required=”” />
<g:select name=”tradingCardType” from=”${tradingCardInventoryInstance.constraints.tradingCardType.inList}” required=”” value=”${tradingCardInventoryInstance?.tradingCardType}” />
<g:checkBox name=”autograph” value=”${collectionsInstance?.autograph}” />
<g:field size=”9″ name=”marketPrice” value=”${fieldValue(bean: tradingCardInventoryInstance, field: ‘marketPrice’)}”/>
<g:submitButton name=”create” value=”${message(code: ‘default.button.create.label’, default: ‘Create’)}” />
</g:form>
If you reload the page in a browser: localhost:8080/dashboard, it should render the form. If you submit data, it should work and the grid should update with your data. It might drop you in a different place though on submit. We can change that buy editing the controller:
Open /controllers/TradingCardInventoryController and go to the save() action. Right before the end of the closure, add this: redirect(uri: “/dashboard”) This says that the last thing it will do on save, is redirect back to the Dashboard.
Now reload and try it out. Save some data in the form, and it should send you back to the same page (so it looks like you never leave) and the grid should update with your data.
Uploading an Image
So lets say we want to upload an image. It’s a bit trickier. We need to do a lot more logic changes. If all you want is the data entry, you’re set right here. If you want to see a image though of a product, you’ll need to store it.
There are two ways of doing this:
- Either you submit the image into the database as raw bytes
- Or you save the image on the file system
Most developers argue that the file system is a better/safer thing to do. It puts less strain on the database. I’ve done both ways, but lets try doing it the file system way….
If we do it by the file system we need to think ahead. When we deploy this application, any files that are user uploaded CAN NOT be in the grails application file structure. The reason for this is that each time you deploy a WAR the grails application file structure is cleaned and rewritten. So anything uploaded to the production environment is lost. I used several tutorials on how to upload files in Grails, and none of them mentioned this problem. So I hit the problem head on when I redeployed. It took many more hours to figure out a solution.
The solution is where you write the files and configuring your apache Tomcat/Jetty to alias that directory as though it was part of the web application folder itself.
Back in the TradingCardInventoryController, go back to the save() action. Above the .save function, add this code:
def uploadedFile = request.getFile(‘payload’)
if(!uploadedFile.empty){
println “Size: ${uploadedFile.size}”
println “FileName: ${uploadedFile.originalFilename}”
def webRootDir = servletContext.getRealPath(“../gallery“)
def userDir = new File(webRootDir, “/test”)
if(!userDir.exists()){
println “I am making a directory for ${userDir}”
userDir.mkdirs()
}
uploadedFile.transferTo(new File(userDir, uploadedFile.originalFilename)
tradingCardInventoryInstance.image = “${uploadedFile.originalFilename}”
}else{
tradingCardInventoryInstance.image = null
}
The code basically is from several tutorials I found online. It tells Grails to take a file coming in from the form (which we’ll add in a sec) with id payload and set it to the variable uploadedFile. We then check the real path to the grails app… we go back one directory (in red above I’ve modified the code to go back a folder to ../gallery.) Then we create a folder called test and store the image there.
So make a folder outside your project folder called gallery to support this locally. We’ll configure Tomcat when we get to the deploy stage.
Also that test folder… that’s pretty lame. It would be better to pass in the username. So each user who uses the system will upload images to their own directory structure. We’ll fix that after we add user registration!
For now, lets go back to the /views/dashboard/index.gsp and modify the form
The form should change from g:form to g:uploadForm and the /g:form should turn to /g:uploadForm.
We will also add this above the submit button:
<label for=”payload”>File:</label>
<input type=”file” id=”payload” name=”payload”/>
If you save and reload, you should be able to click the ‘choose’ icon on the form to find a image. find one and upload it. It should save the file to disk in a folder outside your project/gallery. For example, if your project is:
/Users/bwarner/Sites/grailsapp
It would save this to:
/Users/bwarner/Sites/gallery/
That’s what we want. This will be very important at deploy time.
3 Responses
[…] Development Grails prevnext […]
[…] Adding the Grid + Form + Image Upload […]
[…] Development Grails prevnext […]