Grails dynamic scaffold with hasMany: is it a bug or am I misconfiguring?

让人想犯罪 __ 提交于 2019-12-03 09:51:51

问题


I'm a Grails noob and running into something that seems to be a bug, but it is entirely possible I'm not configuring everything correctly.

I've got two simple Domain Classes:

   class Player {

        String firstName
        String lastName

        static constraints = {
            firstName(blank:false)
            lastName(blank:false)
        }
        String toString() { lastName + ", " + firstName }
    }

and

class Team {

    String mascot;
    static hasMany = [players:Player]

    static constraints = {
        mascot(blank:false)
    }
}

I have controllers for both that do nothing beyond dynamic scaffold these two Domain Classes.

But even when I have a list of Players in my DB, I don't get a multi-select box for them when creating a new Team.

However, the multi-select shows up when I go to edit a Team

Is this a bug in the dynamic scaffolding for new items, do I misunderstand how this is supposed to work, or is there something else I need to declare here?

Any help is hugely appreciated! I've got screenshots that StackOverflow won't let me add because of my newness, but I'd be happy to show them another way if that'll help.


回答1:


I finally figured this out and wanted to pass on what I did just in case someone else runs into it.

When I generated the views for Team, the form block in edit.gsp looks like this:

    <input type="hidden" name="id" value="${teamInstance?.id}" />
                <input type="hidden" name="version" value="${teamInstance?.version}" />
                <div class="dialog">
                    <table>
                        <tbody>

                            <tr class="prop">
                                <td valign="top" class="name">
                                    <label for="mascot">Mascot:</label>
                                </td>
                                <td valign="top" class="value ${hasErrors(bean:teamInstance,field:'mascot','errors')}">
                                    <input type="text" id="mascot" name="mascot" value="${fieldValue(bean:teamInstance,field:'mascot')}"/>
                                </td>
                            </tr> 

                            <tr class="prop">
                                <td valign="top" class="name">
                                    <label for="players">Players:</label>
                                </td>
                                <td valign="top" class="value ${hasErrors(bean:teamInstance,field:'players','errors')}">
                                    <g:select name="players"
from="${Player.list()}"
size="5" multiple="yes" optionKey="id"
value="${teamInstance?.players}" />

                                </td>
                            </tr> 

                        </tbody>
                    </table>
                </div>
                <div class="buttons">
                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
                </div>
            </g:form>

but the form block in create.gsp looks like this:

<g:form action="save" method="post" >
                <div class="dialog">
                    <table>
                        <tbody>

                            <tr class="prop">
                                <td valign="top" class="name">
                                    <label for="mascot">Mascot:</label>
                                </td>
                                <td valign="top" class="value ${hasErrors(bean:teamInstance,field:'mascot','errors')}">
                                    <input type="text" id="mascot" name="mascot" value="${fieldValue(bean:teamInstance,field:'mascot')}"/>
                                </td>
                            </tr> 

                        </tbody>
                    </table>
                </div>
                <div class="buttons">
                    <span class="button"><input class="save" type="submit" value="Create" /></span>
                </div>
        </g:form>

In other words, for this corner case, the default Create view omits the widget to properly display the multi-select list. When I did a copy and paste of the missing code, the dynamically scaffolded controller picked it up and persisted it as expected. So, it's definitely a bug in the view generation code.




回答2:


Yes, the default scaffolding puts a parent selector in the child class' create/edit page.

I'm guessing it was just easier for them this way. It shouldn't be a multi-select though, just a pull-down single-select, as it's a One-to-Many.

As you've explained you wanted more of a Many-to-Many relationship, you might try adding:

static hasMany = [teams:Team]

to your Player class. I've found that Grails does better with bi-directional relationships. It's also useful to have when building search queries, and shouldn't require more than the one relationship table you'd already need.

If you're using Grails pre-v1.1, Many-to-Many relationships aren't directly supported, so even adding the static hasMany above won't be the complete solution, as you'll need to manage adding to the other list when you add to one direction. I haven't used v1.1 yet, so I can't talk about what is needed to specify the Many-to-Many in it.




回答3:


I encountered the same problem using current version (v1.3.4) of Grails. Had to manually modify the create.gsp



来源:https://stackoverflow.com/questions/823137/grails-dynamic-scaffold-with-hasmany-is-it-a-bug-or-am-i-misconfiguring

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!