You know, if you're going to go to the trouble of serialization, you
could just list the keys and types in the author account and build a
form based off that. Actually, the keys probably would be types. You
would then build your form based off the keys required for the author/
use type. It would take a little work but shouldn't be too bad.
Oh and unless that's been fixed in edge hobo, serialized data types
fail with a type mismatch if you don't override the assignment
operator. Here's an example from a recent model.
hobo_model # Don't put anything above this
fields do
name :string
tag :string
tag_attrs :text
timestamps
end
serialize :tag_attrs, Hash
def tag_attrs=(value)
write_attribute(:tag_attrs, value.to_yaml)
end
On Feb 3, 8:07 am, Gert Thiel <[email protected]> wrote:
> Dear Tom. Dear fellow Hobo addicts.
>
> I'm sure, you noticed my need for a Hobo supporting polymorphic
> associations,
> nested forms and similar stuff ;-) That's because I have a serious use
> case:
>
> My employer need an application that allows freelancing authors to
> write
> unique content for our customers websites. Each customer usually has
> his very
> own requirement regarding the authored contents. Some just want simple
> weblog
> content with just a title and a body. Another one needs a meta
> description as
> well. Other customers need something completely different: A
> transcription of
> an audio file or an image.
>
> Until recently I programmed one application with one (git) branch per
> customer
> which had it's own model to comply with the customers requirement. In
> the
> future the application shall host all customers at once. I designed
> some
> models to do so:
>
> I have an «Item» to represent one task an author shall complete. Each
> Item
> belongs to several other models like User and others of course. The
> Item model
> includes every field that is always required like author, reviewer,
> status and
> others.
>
> All fields that are individual to one customers instructions are kept
> in a
> model named «Complement». Every Complement has a name, a type and a
> value like
> so:
>
> class Complement < ActiveRecord::Base
>
> hobo_model
>
> fields do
> name :string
> type :string
> value :serialized
> end
>
> belongs_to :complementable, :accessible => true, :polymorphic =>
> true
>
> end
>
> Did you recognize the polymorphic association? I'm sure you did. So
> you can
> imagine how the Item model looks:
>
> class Item < ActiveRecord::Base
>
> hobo_model
>
> fields do
> duplicates :integer
> status enum_string(:Authoring, :ReturnedToAuthor, :Reviewing,
> \
> :ReturnedToReviewer, :Completed), :default =>
> 'Authoring'
>
> timestamps
> end
> has_many :complements, :as => :complementable
>
> belongs_to :author, :class_name => 'User'
> belongs_to :reviewer, :class_name => 'User'
>
> end
>
> Of course these code fragments are quite incomplete.
>
> Ok, back to «Complement». Every instance of Complement persists one
> "field" of
> an Item instance which actually is not such a field but an associated
> model.
>
> Complement.value stores the actual value, Complement.type tells of
> which type
> (think of a Hobo::Field) the value is and how that value should be
> displayed
> in edit forms. Last but not least that all got a name:
> Complement.name.
>
> I would like to point out, that Complements -- from a user's point of
> view --
> are more equal to there complemented models than e.g. comments to
> there
> commented models. The user shall only see items which include
> complemented
> fields indistinguishable from the first-class fields and edit them as
> would
> the item model include all these fields. In fact in my actual use case
> only an
> excel import routine shall create complements as required. And maybe
> -- in a
> distant future -- privileged users like administrators shall be able
> to add or
> remove complements manually.
>
> Ok, that was much more than just the use case ;-) Time to talk about
> Hobo.
>
> My application uses Hobo as it's foundation. Lots of Hobo's feature
> saved me
> hours and some nerves ;-) Thank you, Tom.
>
> Hobo's polymorphic tags and the growing support of nested forms -- I
> refer to
> <input-many> in fact -- look very promising; I hope to implement the
> stuff
> described above much easier than using plain Rails only.
>
> After updating the Hobo to the latest refs/head/master I adopted the
> show and
> edit views of Item like so:
>
> <show-page>
> <content-body:>
>
> <field-list fields="complements, ...">
> <complements-view:>
> <collection />
> </complements-view:>
> </field-list>
>
> </content-body:>
> </show-page>
>
> <edit-page>
> <form:>
>
> <field-list: fields="complements, ..." no-edit>
> <complements-view:>
> <input-all><field-list no-edit /></input-all>
> </complements-view:>
> </field-list:>
>
> </form:>
> </edit-page>
>
> Remember: These are excerpts from my actual code base only.
>
> I chose <input-all> instead of <input-many> because the user shall
> edit
> existing complements but not add or remove one. One drawback until now
> is,
> that I don't get editors matching Complement.type. So there is still a
> long
> way do go; A lot of work to be done :-(
>
> And updating an item fails with an
> "ActiveRecord::AssociationTypeMismatch in
> ItemsController#update" exception (Complement expected, got Array). I
> include
> the stack trace in the post scriptum below.
>
> My goodness, your still reading this way to long post ;-) May I
> challenge your
> tolerance a little bit more and ask you for constructive criticism,
> ideas,
> hints or thoughts? I appreciate every kind of help.
>
> Kind regards,
>
> Gert Thiel
>
> P.S.:
>
> The request parameters:
>
> {"page_path"=>"items/edit",
> "_method"=>"PUT",
> "authenticity_token"=>"55ceac9f99c61c0e41ac38be6ec725f8deb011d7",
> "id"=>"174",
> "item"=>{"complements"=>{"0"=>{"name"=>"ext_id",
> "complementable_type"=>"Item",
> "complementable_id"=>"174",
> "id"=>"520",
> "value"=>"174"},
> "1"=>{"name"=>"ext_page",
> "complementable_type"=>"Item",
> "complementable_id"=>"174",
> "id"=>"521",
> "value"=>"(interaktive) DVDs"},
> "2"=>{"name"=>"ext_text",
> "complementable_type"=>"Item",
> "complementable_id"=>"174",
> "id"=>"522",
> "value"=>"Dieser <b>Text</b> dient nur zu <i>Testzwecken</i> und
> sollte <u>einzigartig</u> sein!"}}}}
>
> The stack trace:
>
> ActiveRecord::AssociationTypeMismatch (Complement expected, got
> Array):
> /vendor/plugins/hobo/hobo/lib/active_record/association_proxy.rb:
> 20:in `raise_on_type_mismatch'
> /vendor/rails/activerecord/lib/active_record/associations/
> association_collection.rb:310:in `replace'
> /vendor/rails/activerecord/lib/active_record/associations/
> association_collection.rb:310:in `each'
> /vendor/rails/activerecord/lib/active_record/associations/
> association_collection.rb:310:in `replace'
> /vendor/rails/activerecord/lib/active_record/associations.rb:
> 1322:in `complements='
> /vendor/rails/activerecord/lib/active_record/base.rb:2587:in
> `send'
> /vendor/rails/activerecord/lib/active_record/base.rb:2587:in
> `attributes_without_hobo_type_conversion='
> /vendor/rails/activerecord/lib/active_record/base.rb:2583:in
> `each'
> /vendor/rails/activerecord/lib/active_record/base.rb:2583:in
> `attributes_without_hobo_type_conversion='
> /vendor/plugins/hobo/hobo/lib/hobo/model.rb:430:in `send'
> /vendor/plugins/hobo/hobo/lib/hobo/model.rb:430:in `attributes='
> /vendor/plugins/hobo/hobo/lib/hobo/permissions.rb:144:in
> `user_update_attributes'
> /vendor/plugins/hobo/hobo/lib/hobo/permissions.rb:121:in
> `with_acting_user'
> /vendor/plugins/hobo/hobo/lib/hobo/permissions.rb:143:in
> `user_update_attributes'
> /vendor/plugins/hobo/hobo/lib/hobo/model_controller.rb:553:in
> `hobo_update'
> /vendor/plugins/hobo/hobo/lib/hobo/model_controller.rb:157:in
> `update'
> /vendor/rails/actionpack/lib/action_controller/base.rb:1256:in
> `send'
> /vendor/rails/actionpack/lib/action_controller/base.rb:1256:in
> `perform_action_without_filters'
> /vendor/rails/actionpack/lib/action_controller/filters.rb:617:in
> `call_filters'
> /vendor/rails/actionpack/lib/action_controller/filters.rb:638:in
> `run_before_filters'
> /vendor/plugins/hobo/hobo/lib/hobo/controller.rb:22:in `call'
> /vendor/plugins/hobo/hobo/lib/hobo/controller.rb:22:in
> `included_in_class'
> /vendor/rails/activesupport/lib/active_support/callbacks.rb:182:in
> `call'
> /vendor/rails/activesupport/lib/active_support/callbacks.rb:182:in
> `evaluate_method'
> /vendor/rails/actionpack/lib/action_controller/filters.rb:184:in
> `call'
> /vendor/rails/actionpack/lib/action_controller/filters.rb:635:in
> `run_before_filters'
> /vendor/rails/actionpack/lib/action_controller/filters.rb:615:in
> `call_filters'
> /vendor/rails/actionpack/lib/action_controller/filters.rb:610:in
> `perform_action_without_benchmark'
> /vendor/rails/actionpack/lib/action_controller/benchmarking.rb:
> 68:in `perform_action_without_rescue'
> /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/
> ruby/1.8/benchmark.rb:293:in `measure'
> /vendor/rails/actionpack/lib/action_controller/benchmarking.rb:
> 68:in `perform_action_without_rescue'
> /vendor/rails/actionpack/lib/action_controller/rescue.rb:136:in
> `perform_action_without_caching'
> /vendor/rails/actionpack/lib/action_controller/caching/
> sql_cache.rb:13:in `perform_action'
> /vendor/rails/activerecord/lib/active_record/connection_adapters/
> abstract/query_cache.rb:34:in `cache'
> /vendor/rails/activerecord/lib/active_record/query_cache.rb:8:in
> `cache'
> /vendor/rails/actionpack/lib/action_controller/caching/
> sql_cache.rb:12:in `perform_action'
> /vendor/rails/actionpack/lib/action_controller/base.rb:524:in
> `send'
> /vendor/rails/actionpack/lib/action_controller/base.rb:524:in
> `process_without_filters'
> /vendor/rails/actionpack/lib/action_controller/filters.rb:606:in
> `process_without_session_management_support'
> /vendor/rails/actionpack/lib/action_controller/
> session_management.rb:134:in `process'
> /vendor/rails/actionpack/lib/action_controller/base.rb:392:in
> `process'
> /vendor/rails/actionpack/lib/action_controller/dispatcher.rb:
> 184:in `handle_request'
> /vendor/rails/actionpack/lib/action_controller/dispatcher.rb:
> 112:in `dispatch_unlocked'
> /vendor/rails/actionpack/lib/action_controller/dispatcher.rb:
> 125:in `dispatch'
> /vendor/rails/actionpack/lib/action_controller/dispatcher.rb:
> 124:in `synchronize'
> /vendor/rails/actionpack/lib/action_controller/dispatcher.rb:
> 124:in `dispatch'
> /vendor/rails/actionpack/lib/action_controller/dispatcher.rb:
> 134:in `dispatch_cgi'
> /vendor/rails/actionpack/lib/action_controller/dispatcher.rb:41:in
> `dispatch'
> /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/
> ruby/gems/1.8/gems/mongrel-1.1.4/bin/../lib/mongrel/rails.rb:76:in
> `process'
> /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/
> ruby/gems/1.8/gems/mongrel-1.1.4/bin/../lib/mongrel/rails.rb:74:in
> `synchronize'
> /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/
> ruby/gems/1.8/gems/mongrel-1.1.4/bin/../lib/mongrel/rails.rb:74:in
> `process'
> /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/
> ruby/gems/1.8/gems/mongrel-1.1.4/lib/mongrel.rb:159:in
> `process_client'
> /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/
> ruby/gems/1.8/gems/mongrel-1.1.4/lib/mongrel.rb:158:in `each'
> /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/
> ruby/gems/1.8/gems/mongrel-1.1.4/lib/mongrel.rb:158:in
> `process_client'
> /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/
> ruby/gems/1.8/gems/mongrel-1.1.4/lib/mongrel.rb:285:in `run'
> /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/
> ruby/gems/1.8/gems/mongrel-1.1.4/lib/mongrel.rb:285:in `initialize'
> /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/
> ruby/gems/1.8/gems/mongrel-1.1.4/lib/mongrel.rb:285:in `new'
> /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/
> ruby/gems/1.8/gems/mongrel-1.1.4/lib/mongrel.rb:285:in `run'
> /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/
> ruby/gems/1.8/gems/mongrel-1.1.4/lib/mongrel.rb:268:in `initialize'
> /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/
> ruby/gems/1.8/gems/mongrel-1.1.4/lib/mongrel.rb:268:in `new'
> /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/
> ruby/gems/1.8/gems/mongrel-1.1.4/lib/mongrel.rb:268:in `run'
> /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/
> ruby/gems/1.8/gems/mongrel-1.1.4/lib/mongrel/configurator.rb:282:in
> `run'
> /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/
> ruby/gems/1.8/gems/mongrel-1.1.4/lib/mongrel/configurator.rb:281:in
> `each'
> /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/
> ruby/gems/1.8/gems/mongrel-1.1.4/lib/mongrel/configurator.rb:281:in
> `run'
> /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/
> ruby/gems/1.8/gems/mongrel-1.1.4/bin/mongrel_rails:128:in `run'
> /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/
> ruby/gems/1.8/gems/mongrel-1.1.4/lib/mongrel/command.rb:212:in `run'
> /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/
> ruby/gems/1.8/gems/mongrel-1.1.4/bin/mongrel_rails:281
> /vendor/rails/activesupport/lib/active_support/dependencies.rb:
> 142:in `load_without_new_constant_marking'
> /vendor/rails/activesupport/lib/active_support/dependencies.rb:
> 142:in `load'
> /vendor/rails/activesupport/lib/active_support/dependencies.rb:
> 521:in `new_constants_in'
> /vendor/rails/activesupport/lib/active_support/dependencies.rb:
> 142:in `load'
> /vendor/rails/railties/lib/commands/servers/mongrel.rb:64
> /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in
> `gem_original_require'
> /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `require'
> /vendor/rails/activesupport/lib/active_support/dependencies.rb:
> 153:in `require'
> /vendor/rails/activesupport/lib/active_support/dependencies.rb:
> 521:in `new_constants_in'
> /vendor/rails/activesupport/lib/active_support/dependencies.rb:
> 153:in `require'
> /vendor/rails/railties/lib/commands/server.rb:49
> /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in
> `gem_original_require'
> /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `require'
> script/server:3
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Hobo
Users" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/hobousers?hl=en
-~----------~----~----~----~------~----~------~--~---