Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change columns order in generated table (grails constraints not working with mongodb plugin)

I'm using Grails 2.1.1 with mongodb plugin. I have problem with changing order of columns in generated list. As grails scaffolding guide says you need only properly order attributes in contraints block.

My domain:

class Section {

String idName
String visible
String required
String name
String bold

static embedded = ['question']

List<Question> questions
static hasMany = [questions : Question]

static constraints = {
    idName (blank: false)
    name (blank: false)
    visible (blank: false)
    required (blank: false)
    bold (blank: false)
}

@Override
public String toString() {
    name
}
}

but columns are still ordered alphabetically. I'm using static scaffolding, so after changes in constraints i use grails generate-all * command and override all files.

And yes, I tried cleaning and compiling code, also cleaning and restarting server (this integrated with STS) and cleaning browser cache. Is there problem with mongo database (hibernate plugin is uninstalled)?

After that I also installed grails templates. In list.gsp there is line with sorting attributes:

Collections.sort(props, comparator.constructors[0].newInstance([domainClass] as Object[]))

Any idea how can i change this to get working order that I set in constraints?

like image 203
Gorky Avatar asked Nov 23 '12 17:11

Gorky


2 Answers

A jira issue should be filled. If one looks at https://github.com/grails/grails-core/blob/master/grails-crud/src/main/groovy/org/codehaus/groovy/grails/scaffolding/DefaultGrailsTemplateGenerator.groovy

 void generateView(GrailsDomainClass domainClass, String viewName, Writer out) {
    def templateText = getTemplateText("${viewName}.gsp")

    if (templateText) {
        def t = engine.createTemplate(templateText)
        def multiPart = domainClass.properties.find {it.type == ([] as Byte[]).class || it.type == ([] as byte[]).class}

        boolean hasHibernate = pluginManager?.hasGrailsPlugin('hibernate')
        def packageName = domainClass.packageName ? "<%@ page import=\"${domainClass.fullName}\" %>" : ""
        def binding = [pluginManager: pluginManager,
                packageName: packageName,
                domainClass: domainClass,
                multiPart: multiPart,
                className: domainClass.shortName,
                propertyName:  getPropertyName(domainClass),
                renderEditor: renderEditor,
                comparator: hasHibernate ? DomainClassPropertyComparator : SimpleDomainClassPropertyComparator]

        t.make(binding).writeTo(out)
    }

}

It is clear that the call generate views decides to use SimpleDomainClassPropertyComparator. Grails was originally built to depend on hibernate. Over the last couple of years, the world has been using additional persistance mechanisms. If one looks at DomainClassPropertyComparator, there is no dependency on hibernate. I feel the code should test if the domainObject "hasConstraints" to decide which comparator to use or simple use DomainClassPropertyComparator by default. Its behavior is the same if no constraints are found. The call to "hasHibernate" should not be needed by DefaultGrailsTemplateGenerator.

As a work around, you can install the scaffolding templates, edit _form.gsp and change the comparator it is using to DomainClassPropertyComparator e.g. my _form.gsp

    <%=packageName%>
<% import grails.persistence.Event %>
<% import org.codehaus.groovy.grails.scaffolding.DomainClassPropertyComparator %>


<%  excludedProps = Event.allEvents.toList() << 'version' << 'dateCreated' << 'lastUpdated'
    persistentPropNames = domainClass.persistentProperties*.name
    boolean hasHibernate = pluginManager?.hasGrailsPlugin('hibernate')
    if (hasHibernate && org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsDomainBinder.getMapping(domainClass)?.identity?.generator == 'assigned') {
        persistentPropNames << domainClass.identifier.name
    }

DomainClassPropertyComparator mattsComparator = new DomainClassPropertyComparator(domainClass)
comparator = mattsComparator

props = domainClass.properties.findAll { persistentPropNames.contains(it.name) && !excludedProps.contains(it.name) }
    Collections.sort(props, comparator)
    for (p in props) {
        if (p.embedded) {
            def embeddedPropNames = p.component.persistentProperties*.name
            def embeddedProps = p.component.properties.findAll { embeddedPropNames.contains(it.name) && !excludedProps.contains(it.name) }
            Collections.sort(embeddedProps, comparator)
            %><fieldset class="embedded"><legend><g:message code="${domainClass.propertyName}.${p.name}.label" default="${p.naturalName}" /></legend><%
                for (ep in p.component.properties) {
                    renderFieldForProperty(ep, p.component, "${p.name}.")
                }
            %></fieldset><%
        } else {
            renderFieldForProperty(p, domainClass)
        }
    }

private renderFieldForProperty(p, owningClass, prefix = "") {
    boolean hasHibernate = pluginManager?.hasGrailsPlugin('hibernate')
    boolean display = true
    boolean required = false
    if (hasHibernate) {
        cp = owningClass.constrainedProperties[p.name]
        display = (cp ? cp.display : true)
        required = (cp ? !(cp.propertyType in [boolean, Boolean]) && !cp.nullable && (cp.propertyType != String || !cp.blank) : false)
    }
    if (display) { %>
<div class="fieldcontain \${hasErrors(bean: ${propertyName}, field: '${prefix}${p.name}', 'error')} ${required ? 'required' : ''}">
    <label for="${prefix}${p.name}">
        <g:message code="${domainClass.propertyName}.${prefix}${p.name}.label" default="${p.naturalName}" />
        <% if (required) { %><span class="required-indicator">*</span><% } %>
    </label>
    ${renderEditor(p)}
</div>
<%  }   } %>
like image 68
Matthew Payne Avatar answered Sep 22 '22 17:09

Matthew Payne


If you comment the line below in the template and regenerate the view, the order in the constraints will be the order in scaffolding

//Collections.sort(props, comparator.constructors[0].newInstance([domainClass] as Object[]))
like image 28
Cris Avatar answered Sep 23 '22 17:09

Cris