All Futures
  • All Futures
  • Setup
  • Usage
    • Active Record
    • Attributes
    • Associations
    • Aggressions
    • Callbacks
    • Dirty
    • Errors
    • Readonly
    • Validations
    • Versioning
  • API Reference
    • Class Methods
    • Instance Methods
    • Getter Methods
    • Overwritable Methods
  • Examples
    • Faceted Search
Powered by GitBook
On this page
  • Aggregations
  • Arrays
  • Decimal
  • Enums
  • Kredis attributes
  • Secure Passwords

Was this helpful?

  1. Usage

Attributes

PreviousActive RecordNextAssociations

Last updated 3 years ago

Was this helpful?

All Futures stands on the shoulders of two giants, and .

Active Entity presents a "virtual model" that is backed by instead of a relational database. By implementing , an All Futures model should be useful everywhere that you might usually use an Active Record model in your Rails app.

Instead of creating migrations, All Futures model attributes are declared in the class using the attribute method. At minimum, you must specify a Symbol parameter for the name.

You can specify attributes with the following types: :string, :text, :integer, :float, :decimal, :datetime, :date, :time, and :boolean.

Attributes will automatically be :string type unless you pass a second Symbol parameter.

Optionally, you can define a default value, as well as flag an attribute as an array. Other types have their own special options, such as Decimal. Unfortunately, the limit and null options are disregarded.

So far as I can tell, :text is a :string and :time is a :datetime. While you can specify type :binary, Active Entity gets a bit salty, throwing an Encoding::UndefinedConversionError exception when you attempt to save.

Aggregations

Active Model classes include a composed_of method which provides model instances with dynamic methods that map attributes to complex classes.

For example, you could map an address to an Address class:

composed_of :address, mapping: [ %w(address_street street), %w(address_city city) ]

And then you can call these getters and setters to access the members of the Address class:

customer.address_street = "Hyancintvej"
customer.address_city   = "Copenhagen"
customer.address        # => Address.new("Hyancintvej", "Copenhagen")

customer.address = Address.new("May Street", "Chicago")
customer.address_street # => "May Street"
customer.address_city   # => "Chicago"

Arrays

attribute :tags, :string, array: true, default: []

When defining an Array, it's good practice to make sure that your default value is an empty Array. This is true with Postgres-backed Active Record migrations as well.

Decimal

attribute :lat, :decimal, :precision => 15, :scale => 10
attribute :lng, :decimal, :precision => 15, :scale => 10

The precision represents the total number of digits in the number, whereas scale represents the number of digits following the decimal point.

Enums

You can use the enum class method to define a set of possible values for an attribute. It is similar to the enum functionality in Active Model, but has significant enough quirks that you should think of them as distinct.

class Example < AllFutures::Base
  attribute :steve, :integer
  enum steve: [:martin, :carell, :buscemi]
end

example = Example.new
example.attributes # => {"steve"=>nil}
example.steve = :carell
example.carell? # => true
example.attributes # => {"steve"=>"carell"}
example.steve = 2
example.attributes # => {"steve"=>"buscemi"}
example.martin! # => {"steve"=>"martin"} (attributes saved to Redis)
example.steve = :bannon # ArgumentError ('bannon' is not a valid steve)

The first thing you'll notice about the :steve attribute is that it is an "Integer", even though it might seem logical to define it as a String... TL;DR: don't do this. Even though the attribute is ultimately stored in Redis as a String, internally enum tracks the possible values based on their index position in the array. It's also possible to provide a Hash of possible values:

class Example < AllFutures::Base
  attribute :steve, :integer, default: 9
  enum steve: {martin: 5, carell: 12, buscemi: 9}
end

example = Example.new
example.attributes # => {"steve"=>"buscemi"}

The other quirk of this implementation is that you must create your attribute before you call enum.

enum does not create the search scopes that might be familar to Active Model users, since there is no ActiveRecord::Relation or scope concept in All Futures. You can, however, access the mapping directly to obtain the index number for a given value:

Example.steves[:buscemi] # => 9

You can define prefixes and suffixes for your enum attributes. Note the underscores:

class Conversation < AllFutures::Base
  attribute :status, :integer
  attribute :comments_status, :integer
  enum status: [ :active, :archived ], _suffix: true
  enum comments_status: [ :active, :inactive ], _prefix: :comments
end

conversation = Conversation.new
conversation.active_status!
conversation.archived_status? # => false

conversation.comments_inactive!
conversation.comments_active? # => false

Kredis attributes

Kredis attributes can be used in an All Futures model in the exact same way they are used in Active Record models. The format follows a predictable pattern: kredis_datatype:

class Example < AllFutures::Base
  kredis_string :foo
  kredis_flag :bar
end

This will create a new Redis key/value pair that is fully managed by Kredis, and accessed via the foo accessor of your Example instances. The kredis_counter, kredis_unique_list and kredis_slots are all really useful tools.

You can set and retrieve values from Kredis attributes using the value method:

example = Example.new
example.foo.value = "baz"

All instances of your All Futures model will share the same Kredis attribute values. Advanced users can experiment with using a Proc to pass a unique value when the class is instantiated.

It's important to remember that Kredis attributes are not tracked as All Futures attributes, and they are stored in entirely different Redis keys.

Secure Passwords

class Example < AllFutures::Base
  has_secure_password
  attribute :password_digest

You can now set values for the password and password_confirmation attributes. valid? will return false and the errors accessor will contain an ActiveModel::Error exception if the two values aren't present or don't match.

You can check to see if a password is valid using the authenticate(value) method.

In order to use the secure password mechanism, your application must require the bcrypt gem. If you use Devise, it's already in your project.

You can in the Rails Guide.

All Futures models can store and authenticate . You store the digest value in an attribute instead of using attr_accessor.

Active Entity
Kredis
Redis
Active Model
learn more
secure passwords