Ruby Forum Radiant CMS > Radiant 0.6.6 / Rails 2.0 Model Inheritance Question

Posted by Chris Parrish (Guest)
on 29.04.2008 00:06
(Received via mailing list)
Looks like I just sent out an email as  HTML.  Let's try this again with
plain text...


I'm reworking my Styles and Javascripts Extension to play nice with
Rails 2.0, and incorporate some things that John suggested and I'm
hitting a weird brick wall...

I have a TextAsset Model (with corresponding table) from which I inherit
JavascriptAsset and StylesheetAsset Models (single table inheritance).
I just moved one of my validation rules out of the parent (TextAsset)
into StylesheetAsset and suddenly my tests are failing.

This should be easy but I'm stumped.  (This is my first foray into rSpec
but I've basically mimicked the way Radiant is testing it's models).

Help anyone?


Here are the relevant pieces of offending code...

## From stylesheet_asset.rb
class StylesheetAsset < TextAsset
  validates_uniqueness_of :name, :message => 'filename already in use'
end


## From stylesheet_asset_spec.rb
require File.dirname(__FILE__) + '/../spec_helper'

describe StylesheetAsset do
  scenario :stylesheets
  test_helper :validations

  before(:each) do
    @stylesheet_asset = @model = StylesheetAsset.new(stylesheet_params)
  end

...

  it 'should validate uniqueness of' do
    assert_invalid :name, 'filename already in use', 'main.css'  <--
this fails!!!
    assert_valid :name, 'just-a-test'
  end

end


## From stylesheets_scenario.rb
class StylesheetsScenario < Scenario::Base

  def load
    create_stylesheet "main.css", :raw_content => 
'body{background:white}'
  end

  helpers do
    def create_stylesheet(name, attributes={})
      create_record :stylesheet_asset, name.symbolize,
stylesheet_params(attributes.reverse_merge(:name => name))
    end

    def stylesheet_params(attributes={})
      name = attributes[:name] || unique_stylesheet_name
      {
        :name => name,
        :raw_content => "dummy content"
      }.merge(attributes)
    end

    private

      @@unique_stylesheet_name_call_count = 0
      def unique_stylesheet_name
        @@unique_stylesheet_name_call_count += 1
        "stylesheet-#{@@unique_stylesheet_name_call_count}"
      end

  end

end

What I was hoping to do here was have the two child classes (Javascripts
and Stylesheets) each enforce their own unique naming sets (since
they'll be effectively served from their own directories).  This way,
the form validation wouldn't complain if you had both a "my_file"
stylesheet and a "my_file" javascript since they would be served from
/stylesheets/my_file and /javascripts/my_file respectively.  (Two
stylesheets or two javascripts with the same name would be a no-no, 
though).

Is this some misunderstanding of Single Table Inheritance on my part, a
flaw with Radiant's extension testing, or what?

Thanks for any assistance,
-Chris
Posted by Sean Cribbs (seancribbs)
on 29.04.2008 01:27
(Received via mailing list)
Chris,

Instead of moving it to the child class, I would put the validation in
the TextAsset class, but put the scope on the validation to :type, i.e.

validates_uniqueness of :name, :scope => :type, :message => 'filename
already in use'

Sean
Posted by Chris Parrish (Guest)
on 29.04.2008 16:42
(Received via mailing list)
Thanks Sean,  I completely forgot about :scope.

This didn't completely fix it for me, though.  So, in case this helps
anyone in the future, I still had to change the following...

   1. I'm mirroring Radiant's use of:
          set_inheritance_column :class_name
      instead of using the default Rails 'type' column for single table
      inheritance.  So of course my code reads:
          validates_uniqueness of :name, :scope => :class_name, :message
      => 'filename already in use'

   2. This still didn't work, though.  And it was only by poking around
      the Archive extension that I figured out that the create_record
      call in the scenario had to explicitly call out the value for this
      class_name field like (shown here in my create_stylesheet helper):
            def create_stylesheet(name, attributes={})
              create_record :stylesheet_asset,
                            name.symbolize,

      stylesheet_params(attributes.reverse_merge(:name => name,

      :class_name => 'StylesheetAsset') )
            end

I'm still not sure why #2 was required (possible bug with Scenario
plugin)?  I would have thought that creating the record would have
automatically used Rails STI and populated the class name for me.

It's also possible that I wouldn't have needed this if I'd have stuck to
the default STI implementation and just used the 'type' field -- didn't
try that one.

-Chris
Posted by Sean Cribbs (seancribbs)
on 29.04.2008 16:53
(Received via mailing list)
>                                                                      
>      :class_name => 'StylesheetAsset') )
>            end
>
> I'm still not sure why #2 was required (possible bug with Scenario 
> plugin)?  I would have thought that creating the record would have 
> automatically used Rails STI and populated the class name for me.
>
Ah, that makes sense.  Next time you can probably use create_model
instead, which creates the actual AR object instead of just writing the
record to the DB.

Sean