GithubHelp home page GithubHelp logo

rpanachi / attr_bucket Goto Github PK

View Code? Open in Web Editor NEW

This project forked from ernie/attr_bucket

1.0 2.0 0.0 850 KB

Your model can has a bucket (of attributes)

Home Page: http://metautonomo.us/projects/attr_bucket

License: MIT License

attr_bucket's Introduction

attr_bucket

Sometimes you’re tempted to use STI in your Rails app, but your STI classes don’t share all of the same attributes. So, you’re left with two choices:

1. Add all of the columns your descendant classes will need.

2. Remember that this occurrence is a telltale sign that STI is the wrong design pattern to be using…

OR IS IT? Yes, it is. Probably.

But wait! I present you with a third option:

3. Give your model a bucket. So it can hold all its extra attributes.

Hoo boy. This is probably a horrible idea.

Usage

Let’s say we have a table containing animals. Animals have some universal traits, such as a number of legs. We want to be able to search on those. But they also have some specific traits that we’d like to display on the animal’s detail page. We don’t (and this part is important) care about searching on these traits, we just want to display them. OK, let’s have at it:

class Animal < ActiveRecord::Base
  # t.string  :type
  # t.string  :name
  # t.integer :number_of_legs
  # t.boolean :can_fly
  # t.boolean :is_cuddly
  # t.text    :unique_traits
end

We’ll only track one unique attribute for birds, for now. This will be a string, because strings are the default type for attributes in a bucket.

class Bird < Animal
  attr_bucket :unique_traits => :group_name # "Murder" of crows, for instance
end

We might want to know “fresh” or “salt” for fish, (and whether they go best with rice or asparagus). These will also be strings.

class Fish < Animal
  attr_bucket :unique_traits => [:best_served_with, :water_type]
end

Now, we have a special animal that we want to add some non-string attributes to, so we’ll define our bucket with a hash, instead:

class Lolrus < Animal
  # Yes, this actually works. It's an alias. Come on, I had to.
  i_has_a_bucket :unique_traits => {
    :in_possession_of_bucket => :boolean, # Has it been stolen yet?
    :tusk_length_in_inches   => :integer,
    :also_known_as           => proc {|v| "aka #{v}"}
  }
end

Note the use of the proc on the value side of the hash for :also_known_as. You can supply any object that responds to call for custom typecasting behavior.

Now, we can create some animals. Let’s start with a crow.

crow = Bird.create(
  :name => 'Crow',
  :number_of_legs => 2,
  :can_fly => true,
  :is_cuddly => false,
  :group_name => 'Murder'
)
=> #<Bird id: 1, type: "Bird", name: "Crow", ...>

Looks about like we’d expect. Now we can retrieve our bucketed attributes by name, without worrying about the bucket they’re in.

crow.group_name
=> "Murder"

Let’s create a fish of some kind. How about a salmon?

salmon = Fish.create(
  :name => 'Salmon',
  :number_of_legs => 0,
  :can_fly => false,
  :is_cuddly => false,
  :water_type => 'fresh',
  :best_served_with => 'Pan-fried asparagus'
)
=> #<Fish id: 3, type: "Fish", name: "Salmon", ...>

As before, we can retrieve the bucketed attribute:

salmon.best_served_with
=> "Pan-fried asparagus"

We can also change the attribute using a standard attribute writer, so this works just fine with Rails forms.

salmon.best_served_with = 'A light red wine'
=> "A light red wine"
salmon.save
=> true

Let’s pull it back out of the database and make sure everything looks right:

fish = Fish.find 3
=> #<Fish id: 3, type: "Fish", name: "Salmon", ...>
fish == salmon
=> true

And it maintained our updated attribute.

fish.best_served_with
=> "A light red wine"

Now let’s try an animal with some typecasting – I’ll create using string values for the bucketed attributes since that’s what a Rails form would send:

lolrus = Lolrus.create(
  :name => 'The LOLRUS',
  :number_of_legs => 0, # Do flippers count as legs?
  :can_fly => false,
  :is_cuddly => true,
  :also_known_as => 'The Holder of the Bucket',
  :in_possession_of_bucket => 't',
  :tusk_length_in_inches => '6'
)
=> #<Lolrus id: 5, type: "Lolrus", name: "The LOLRUS", ...>

Let’s make sure the attributes got cast to the proper type:

lolrus.tusk_length_in_inches
=> 6
lolrus.in_possession_of_bucket
=> true
lolrus.also_known_as
=> "aka The Holder of the Bucket"

That lolrus looks to be in fine shape, indeed.

Caveats

This whole thing’s a caveat, really. If you’re looking to do this, be absolutely, positively sure that you really want to bucket your attributes rather than inherit from an abstract class or something a bit, well, more sane.

attr_bucket isn’t for you if:

  • You ever intend to search against your custom attributes

  • You plan to instantiate tons of records at a time (the serialization overhead will hurt – though it’ll hurt less with psych)

  • You want to get invited to all the cool software engineer parties

All that caveat-ing aside, give it a try, and let me know if you find a particularly clever use case!

Copyright (or blame, depending on how you look at it)

Copyright © 2011 Ernie Miller. See LICENSE for details.

attr_bucket's People

Stargazers

Rodrigo Panachi avatar

Watchers

Rodrigo Panachi avatar James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.