Pregunta

I'm working on a Hobo app trying to tie together a few models properly.

Activity objects have many Page children. They also have many DataSet children.

Page objects have several different kinds of children. We'll talk about Widget children, but there are several types with the same issue. An instance of a Widget belongs to a Page but also has a belongs_to relationship with a DataSet. Here's the important point: the DataSet must belong to the containing Activity. So for any given @widget:

@widget.page.activity === @widget.data_set.activity

It's easy enough to enforce this constraint in the model with a validation on save. The trick is presenting, within the Widget's form, a select menu of available DataSets which only contains DataSets for the current Activity

I was able to get this working for existing objects using a tag like this:

<data_set-tag: options="&DataSet.activity_is(&this.page.activity)" />

However, for a new Widget, this fails messily, because either &this or &this.page is not yet set. Even for a route which contains the page ID, like /pages/:page_id/widgets/new, I'm not really able to get an Activity to scope the list of DataSets with.

If this was proper Rails, I'd get in to the relevant controller method and make the Activity available to the view as @activity or something of the sort, but in Hobo the controllers seems to be 95% Magic™ and I don't know where to start. The knowledge of which Activity is current must be in there somewhere; how do I get it out?

This is Hobo 1.3.x on Rails 3.0.x.


ETA: The code producing the errors is in the form tag for Widget, like so:

<extend tag="form" for="Widget">
  <old-form merge>
    <field-list: fields="&this.field_order">
      <data_set-tag: options="&DataSet.activity_is(&this.page.activity)" />
    </field-list>
  </old-form>
</extend>

As I said above, this works for editing existing Widgets, but not new Widgets; the error is undefined method 'page' for nil:NilClass. Bryan Larsen's answer seems to suggest that &this.page should not be null.

¿Fue útil?

Solución 2

In the end, it turned out to be syntax. Instead of

<data_set-tag: options="&DataSet.activity_is(&this.page.activity)" />

I needed

<data_set-tag: options="&DataSet.activity_is(@this.page.activity)" />

(note the @).

We actually made this into a helper method, so the final code is

<data_set-tag: options="&DataSet.activity_is(activity_for(@this))" />

Otros consejos

it looks like you tried to post this question to the Hobo Users mailing list -- I got a moderation message, but it doesn't appear that your post got posted, nor can I find it to let it through. Please try reposting it, there are several helpful people on the list that don't monitor the Hobo tag here.

In Hobo 1.3, the new action doesn't support part AJAX, so there really isn't much magic. You can just replace the action with your own:

def new_for_page
  @activity = Activity.find(...)
  @page = Page.find(params[:page_id])
  @widget = @page.widgets.new
end

There is a little bit of magic referenced above: if you're in WidgetsController, assigning to @widget will also assign to this.

But as you said, the knowledge is obviously in there somewhere, and your custom controller action shouldn't be necessary.

This statement seems wrong: However, for a new Widget, this fails messily, because either &this or &this.page is not yet set.

It looks like you're properly using owner actions. /pages/:page_id/widgets/new is the route. In widgets_controller it's the new_for_page action. In a new or new_for action, this is set to an unsaved version of the object. In your action, it should have been created with the equivalent of Page.find(params[:page]).widgets.new. In other words, both this and this.page should be populated.

I'm sure you didn't make your statement up out of thin air, so there's probably something else going on.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top