Skip to content
This repository has been archived by the owner on Jan 2, 2020. It is now read-only.

Better support for ActiveRecord associations #16

Open
itspriddle opened this issue Mar 9, 2012 · 1 comment
Open

Better support for ActiveRecord associations #16

itspriddle opened this issue Mar 9, 2012 · 1 comment

Comments

@itspriddle
Copy link

I've been working on adding better support to attrtastic for attributes that are ActiveRecord associations. Currently, attrtastic just calls .to_s on them, and you end up with something like #<Post:0x007f893f477a78>.

Here are the relevant pieces of an app to illustrate what I'm talking about.

Given the following models/associations:

# app/models/author.rb
# Attributes: :id, :name
class Author < ActiveRecord::Base
  has_many :posts
end

# app/models/post.rb
# Attributes: :id, :name
class Post < ActiveRecord::Base
  belongs_to :author
end

# Created as:
author = Author.create! name: "Josh"
post   = Post.create! name: "First Post", author_id: author.id

and given this ERB:

# app/views/posts/show.html.erb
<%= semantic_attributes_for @post do |attr| %>
  <%= attr.attributes do %>
    <%= attr.attribute :name %>
    <%= attr.attribute :author %>
  <% end %>
<% end %>

My changes would generate this HTML:

<div class="attrtastic post">
  <div class="attributes"><ol>
    <li class="attribute"><span class="label">Name</span><span class="value">First Post</span></li>
    <li class="attribute"><span class="label">Author</span><span class="value">Josh</span></li>
</ol></div></div>

Here's the code that provides this behavior:

Attrtastic.default_options.merge!(
  # If an attribute is an ActiveRecord itself, check for any of these columns
  # to print it's value. Otherwise, fallback to .to_s
  active_record_name_columns: [:full_name, :name, :title]
)

module Attrtastic
  class SemanticAttributesBuilder
    def format_attribute_value_custom(value)
      opts = Attrtastic.default_options.fetch(:active_record_name_columns, [:name])
      case value
      when ActiveRecord::Base
        if meth = opts.find { |m| value.respond_to?(m) }
          value.send(meth).to_s
        else
          "#{value.class.name.humanize} ##{value.id}"
        end
      else
        format_attribute_value_default value
      end
    end
    alias_method :format_attribute_value_default, :format_attribute_value
    alias_method :format_attribute_value, :format_attribute_value_custom
  end
end

If that's something you think might be useful for other users, I'd be happy to clean it up and submit a proper patch.

@MBO
Copy link
Owner

MBO commented Mar 13, 2012

I don't think it's good idea.

First: I don't want to depend on ActiveRecord (Attrtastic doesn't depend on ActiveRecord, you can pass POROs),

Second: if you don't provide sane to_s for your objects, then you have similar problem with link_to helper and other ways where you output your associated object (you have to pass method name instead of defaulting on to_s).

You can archive the same with either:

  1. :format option, when you provide proper formatter for value, i.e:

    def ar_formatter(object)
      method_name = %w( full_name name ).find {|m| object.respond_to?(:m) }
      object.send(method_name || "to_s")
    end
    
  2. :value option, where you can provide symbol used as method name to retrieve value from object

Of course you can combine both of these, Attrtastic first applies :value if it's present to retrieve actual value of attribute and then it is formatted according to :format option (it can be false to no format at all an only call to_s, or is formatted with some defaults)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants