views:

105

answers:

3

Hi,

I'm trying to clean up my code and get rid of a lot of ugly hashes. In my views I define several actions like this:

@actions = {
  :interest => {'Show interest', link_to(..), :disabled => true},
  :follow   => {'Follow this case', link_to(..)}
  ...
}

As these hashes grow, the maintainability decreases. I want to convert the above format to something like:

actions do
   item :interest, 'Show interest', link_to(..), :disabled => true
   item :follow,   'Follow',        link_to(..)
   ...
end

How do I structure my helper methods to allow this? Preferably the 'item'-method should only be available in the 'actions' block and not in the global scope.

Thanks!

+1  A: 
Derick Bailey
Thanks. How would I access the @actions property from within both the item method and the actions method, so I can pass it on to the view?
Mattias
actually, i think Konstantin's solution is better. mine would need some major rework to be usable in a controller
Derick Bailey
+1  A: 

Here is a similar solution, actually creating your data structure and avoiding the creation of a new class on every call of actions:

def action
  class << @actions ||= {}
    def item(name, *args) self[name] = args end
  end
  @actions.instance_eval(&Proc.new) if block_given?
  @actions
end

You can now use the dsl to construct that structure:

actions do
  item :interest, 'Show interest', link_to(..), :disabled => true
end

actions # => { :interest => [ 'Show interest', link_to(..), :disabled => true ] }

actions.item :follow, 'Follow', link_to(..)
Konstantin Haase
Mattias
Yeah, that is because `instance_eval` changes `self`. You can do `yield(@actions)` and use it like `actions { |a| a.item }` instead.
Konstantin Haase
A: 

I experimented a bit and ended up with a solution that works so far:

def actions(&block)
   @actions ||= []
   def item(id, content = '', options = {})
     @actions << [id, {
       :content => content || ''
     }.merge(options)]
   end
   block.call
end

Which in terms allows me to do the following in my views:

actions do
  item :primary, link_to('Write letter', ...), :disabled => true
end

And the @actions-variable is filled with these values.

Mattias