Dies ist der Cache von Google von http://jonathanbarket.com/post/78831424/simple-associations-with-ext-scaffold. Es handelt sich dabei um ein Abbild der Seite, wie diese am 30. Okt. 2009 09:42:15 GMT angezeigt wurde. Die aktuelle Seite sieht mittlerweile eventuell anders aus. Weitere Informationen

Nur-Text-Version
Diese Suchbegriffe sind markiert: simple associations extscaffold
February 16th, 2009

Simple Associations with ext_scaffold

In my last post I went into the decision making process that led me to ExtJS and the joy that is ext_scaffold. The first real mystery I faced using it came when I needed some simple associations. Thankfully, Martin sent me a diff that allowed me to wrap my head around the process. Now, I’m going to attempt to pass this knowledge on in a more descriptive way.

Let’s assume for the sake of this example that you’ve used ext_scaffold to generate two models: Manufacturers and Countries. Keep in mind that I use a lot of the wonderful Rails aliases from Peepcode, so sg may be script/generate for you.

sg ext_scaffold Manufacturer name:string country_id:integer
sg ext_scaffold Country name:string

Now we need to setup our associations in our models as such:

# app/models/manufacturer.rb
class Manufacturer < ActiveRecord::Base
  belongs_to :country

  def country_name
    country && country.name
  end
end

# app/models/country.rb
class Country < ActiveRecord::Base
  has_many :manufacturers
end

The one addition to our standard Rails setup is country_name. This instance method returns the humanized value for our associated model. In other words, it’s what we want to show up in the grid. If we were listening articles instead of countries, it might be article && article.title.

Next, we need to collect an appropriately formatted list of Countries that Manufacturers can belong to. Open up views/manufacturers/index.html.erb and make the following adjustment:

items: new "color:black;background-color:#99ff99">ExtScaffold.Manufacturer({
  countryNamesStore: <%= Country.all.collect {
    |c| [c.id, c.name] }.to_json %>,
  url: '<%= manufacturers_path %>'
  <%= ",baseParams: { #{request_forgery_protection_token}: '#{form_authenticity_token}' }" if protect_against_forgery? %>
})

The new countryNamesStore we’ve added is a multidimensional array that contains the id and name for each Country. This information is going to be passed to an ExtJS combobox which takes the first parameter as the value and the second parameter as the text.

Here’s where it gets a little tricky. Fire up public/javascripts/ext_scaffold/manufacturer.js. We’re going to start by adding an additional field to our Ext.data.JsonReader that contains our virtual attribute country_name.

reader: new Ext.data.JsonReader({
  root: 'manufacturers',
  id: 'id',
  totalProperty: 'results'
},[
  { name: 'id', mapping: 'manufacturer.id' },
  { name: 'manufacturer[name]', mapping: 'manufacturer.name' },
  { name: 'manufacturer[country_id]',
    mapping: 'manufacturer.country_id', type: 'int' },
  { name: 'virtual_attributes[country_name]',
    mapping: 'manufacturer.country_name' }
]),

We also need to modify the Ext.grid.ColumnModel so it shows our virtual attribute rather than the actual country_id.

var cm = new Ext.grid.ColumnModel([
  { id: 'id', header: scaffoldPanel.labels['id'],
    width: 40, dataIndex: 'id'},
  { header: scaffoldPanel.labels['manufacturer[name]'],
    dataIndex: 'manufacturer[name]' },
  { header: 'Country',
    dataIndex: 'virtual_attributes[country_name]' }
]);

Take note that we replaced the header line for country_id, rather than simply adding a new one.

The last change for manufacturer.js is down where it defines the form panel. We’re going to change the fields defined in items.

items: [
{ fieldLabel: scaffoldPanel.labels['manufacturer[name]'],
  name: 'manufacturer[name]', xtype: 'textfield' },
{ fieldLabel: 'Country', name:'virtual_attributes[country_name]',
  hiddenName: 'manufacturer[country_id]', xtype: 'combo',
  store: scaffoldPanel.countryNamesStore, triggerAction: 'all',
  forceSelection: true }
],

Similarly, we’ve removed the form field for country_id and replaced it with a combobox populated by our countryNamesStore.

Finally, open up manufacturers_controller.rb. We’re going to modify the index action so that the to_json method will execute country_name and include its name and value in the response:

def index
  respond_to do |format|
    format.html     # index.html.erb (no data required)
    format.ext_json { render :json =>  @manufacturers.to_ext_json(:methods => :country_name, :class => Manufacturer, :count => Manufacturer.count(options_from_search(Manufacturer))) }
  end
end

It may seem like a lot of changes at first, but once you’ve been through the process and wrapped your brain around the concept, it should become very straightforward. If you haven’t already started using ext_scaffold, this should give you one less reason not to.