Giter Site home page Giter Site logo

active_type's Introduction

ActiveType Tests

Make any Ruby object quack like ActiveRecord

ActiveType is our take on "presenter models" (or "form models") in Rails. We want to have controllers (and forms) talk to models that are either not backed by a database table, or have additional functionality that should not be shared to the rest of the application.

However, we do not want to lose ActiveRecord's amenities, like validations, callbacks, etc.

Examples for use cases are models to support sign in:

class SignIn < ActiveType::Object

  # this is not backed by a db table

  attribute :username, :string
  attribute :password, :string

  validates :username, presence: true
  validates :password, presence: true

  # ...

end

Or models to support sign up:

class User < ActiveRecord::Base
  # ...
end

class SignUp < ActiveType::Record[User]

  # this inherits from User

  validates :password, confirmation: true

  after_create :send_confirmation_email

  def send_confirmation_email
    # this should happen on sign-up, but not when creating a user in tests etc.
  end

  # ...

end

A note on Rails's own .attribute

Rails 5+ comes with its own implementation of .attribute. This implementation is functionally very similar, but not identical to ActiveType's.

We have decided to continue to use our own implementation. This means that if you use ActiveType, ActiveRecord::Base.attribute will be overriden.

The following behaviours are different than in vanilla Rails 5:

  • Defaults procs are evaluated in instance context, not class context.
  • Defaults are evaluated lazily.
  • You can override attributes with custom methods and use super.
  • Attributes will work on records retrieved via .find.
  • Attributes will be duped if you dup the record.
  • You cannot use attribute :db_column to override the behaviour of an existing database-backed attribute.

If you need to use ActiveRecord's own .attribute method, you can still access is as ar_attribute:

class User < ApplicationRecord
  # use my custom type to serialize to the database
  ar_attribute :password, MyPasswordType.new
end

ActiveType::Object

Inherit from ActiveType::Object if you want an ActiveRecord-kind class that is not backed by a database table.

You can define "columns" by saying attribute:

class SignIn < ActiveType::Object

  attribute :email, :string
  attribute :date_of_birth, :date
  attribute :accepted_terms, :boolean
  attribute :account_type

end

These attributes can be assigned via constructor, mass-assignment, and are automatically typecast:

sign_in = SignIn.new(date_of_birth: "1980-01-01", accepted_terms: "1", account_type: AccountType::Trial.new)
sign_in.date_of_birth.class # Date
sign_in.accepted_terms? # true

ActiveType knows all the types that are allowed in migrations (i.e. :string, :integer, :float, :decimal, :datetime, :time, :date, :boolean). You can also skip the type to have a virtual attribute without typecasting.

ActiveType::Object actually inherits from ActiveRecord::Base, but simply skips all database access, inspired by ActiveRecord Tableless.

This means your object has all usual ActiveRecord::Base methods. Some of those might not work properly, however. What does work:

  • validations
  • callbacks (use before_save, after_save, not before_create, or before_update)
  • "saving" (returning true or false, without actually persisting)
  • belongs_to (after saying attribute :child_id, :integer)

Note on transactions

Since ActiveType::Object is not backed by a database, it does not open a real transaction when saving, so you should not rely on database changes that might have happend in a #save callback to be rolled back when #save fails. If you need this, make sure to wrap those changes in an explicit transaction yourself.

ActiveType::Record

If you have a database backed record (that inherits from ActiveRecord::Base), but also want to declare virtual attributes, simply inherit from ActiveType::Record.

Virtual attributes will not be persisted.

ActiveType::Record[BaseClass]

ActiveType::Record[BaseClass] is used to extend a given BaseClass (that itself has to be an ActiveRecord model) with additional functionality, that is not meant to be shared to the rest of the application.

Your class will inherit from BaseClass. You can add additional methods, validations, callbacks, as well as use (virtual) attributes like an ActiveType::Object:

class SignUp < ActiveType::Record[User]
  # ...
end

If you need to access the extended BaseClass from your presenter model, you may call extended_record_base_class on its class:

SignUp.extended_record_base_class # => "User (...)"

# or
sign_up = SignUp.new
sign_up.class # => "SignUp (...)"
sign_up.class.extended_record_base_class # => "User (...)"

Inheriting from ActiveType:: objects

If you want to inherit from an ActiveType class, simply do

class SignUp < ActiveType::Record[User]
  # ...
end

class SpecialSignUp < SignUp
  # ...
end

Defaults

Attributes can have defaults. Those are lazily evaluated on the first read, if no value has been set.

class SignIn < ActiveType::Object

  attribute :created_at, :datetime, default: proc { Time.now }

end

The proc is evaluated in the context of the object, so you can do

class SignIn < ActiveType::Object

  attribute :email, :string
  attribute :nickname, :string, default: proc { email.split('@').first }

end

SignIn.new(email: "[email protected]").nickname # "tobias"
SignIn.new(email: "[email protected]", :nickname => "kratob").nickname # "kratob"

Overriding accessors

You can override attribute getters and setters using super:

class SignIn < ActiveType::Object

  attribute :email, :string
  attribute :nickname, :string

  def email
    super.downcase
  end

  def nickname=(value)
    super(value.titleize)
  end

end

Nested attributes

ActiveType supports its own variant of nested attributes via the nests_one / nests_many macros. The intention is to be mostly compatible with ActiveRecord's accepts_nested_attributes functionality.

Assume you have a list of records, say representing holidays, and you want to support bulk editing. Then you could do something like:

class Holiday < ActiveRecord::Base
  validates :date, presence: true
end

class HolidaysForm < ActiveType::Object
  nests_many :holidays, reject_if: :all_blank, default: proc { Holiday.all }
end

class HolidaysController < ApplicationController
  def edit
    @holidays_form = HolidaysForm.new
  end

  def update
    @holidays_form = HolidaysForm.new(params[:holidays_form])
    if @holidays_form.save
      redirect_to root_url, notice: "Success!"
    else
      render :edit
    end
  end

end

# and in the view
<%= form_for @holidays_form, url: '/holidays', method: :put do |form| %>
  <ul>
    <%= form.fields_for :holidays do |holiday_form| %>
      <li><%= holiday_form.text_field :date %></li>
    <% end %>
  </ul>
<% end %>
  • You have to say nests_many :records

  • records will be validated and saved automatically

  • The generated .records_attributes = expects parameters like ActiveRecord's nested attributes, and works together with the fields_for helper:

    • either as a hash (where the keys are meaningless)

      {
        '1' => { date: "new record's date" },
        '2' => { id: '3', date: "existing record's date" }
      }
    • or as an array

      [
        { date: "new record's date" },
        { id: '3', date: "existing record's date" }
      ]

To use it with single records, use nests_one. It works like accept_nested_attributes does for has_one. Use .record_attributes = to build the child record.

Supported options for nests_many / nests_one are:

  • build_scope

    Used to build new records, for example:

    nests_many :documents, build_scope: proc { Document.where(:state => "fresh") }
  • find_scope

    Used to find existing records (in order to update them).

  • scope

    Sets find_scope and build_scope together.

    If you don't supply a scope, ActiveType will guess from the association name, i.e. saying

    nests_many :documents

    is the same as saying

    nests_many :documents, scope: proc { Document }

    which is identical to

    nests_many :documents, build_scope: proc { Document }, find_scope: proc { Document }

    All ...scope options are evaled in the context of the record on first use, and cached.

  • allow_destroy

    Allow to destroy records if the attributes contain _destroy => '1'

  • reject_if

    Pass either a proc of the form proc { |attributes| ... }, or a symbol indicating a method, or :all_blank.

    Will reject attributes for which the proc or the method returns true, or with only blank values (for :all_blank).

  • default

    Initializes the association on first access with the given proc:

    nests_many :documents, default: proc { Documents.all }

Options supported exclusively by nests_many are:

  • index_errors

    Use a boolean to get indexed errors on related records. In Rails 5 you can make it global with config.active_record.index_nested_attribute_errors = true.

Casting records or relations

When working with ActiveType you will often find it useful to cast an ActiveRecord instance to its extended ActiveType::Record variant.

Use ActiveType.cast for this:

class User < ActiveRecord::Base
  ...
end

class SignUp < ActiveType::Record[User]
  ...
end

user = User.find(1)
sign_up = ActiveType.cast(user, SignUp)
sign_up.is_a?(SignUp) # => true

This is basically like ActiveRecord#becomes, but with less bugs and more consistent behavior.

Note that cast is destructive. The originally casted record (user) and the returned record (sign_up) share internal state (such as attributes). To avoid unexpected behavior, the original record will raise an error when trying to change or persist it. Also, casting of a record that has changes in its loaded associations is prevented, because those changes would be lost.
If you know what you are doing and absolutely want that, you may use the option force: true to allow this potentially problematic behaviour, e.g. sign_up = ActiveType.cast(user, SignUp, force: true)

You can also cast an entire relation (scope) to a relation of an ActiveType::Record:

adult_users = User.where('age >= 18')
adult_sign_ups = ActiveType.cast(adult_users, SignUp)
sign_up = adult_sign_ups.find(1)
sign_up.is_a?(SignUp) # => true

If you need to add some special logic after casting you can add an after_cast method:

class SignUp < ActiveType::Record[User]
  def after_cast(user)
    # Called with the original user upon casting.
  end
end

Associations

Sometimes, you have an association, and a form model for that association. Instead of always casting the associations manually, you can use the change_association macro to override an association's options. For example.

class Credential < ActiveRecord::Base
end

class User < ActiveRecord::Base
  has_many :credentials
end

class SignUpCredential < ActiveType::Record[Credential]
end

class SignUp < ActiveType::Record[User]
  change_association :credentials, class_name: 'SignUpCredential'
end

Now, if you load credentials, you will automatically receive records of type SignUpCredential.

Supported Rails versions

ActiveType is tested against ActiveRecord 5.2, 6.0, 6.1, and 7.0.

Later versions might work, earlier will not.

Supported Ruby versions

ActiveType is tested against 2.5, 2.7, 3.0, and 3.1.

Installation

In your Gemfile say:

gem 'active_type'

Now run bundle install and restart your server.

Development

  • We run tests against several ActiveRecord and Ruby versions using gemika.
  • You can bundle all versions with rake matrix:install.
  • You can run specs against all Gemfiles compatible with your current ruby version with rake matrix:spec.
  • You can run specs against a single Gemfile with BUNDLE_GEMFILE=Gemfile<variant> bundle exec rspec spec.
  • When you make a pull request, tests are automatically run against all variants and Rubies on travis.ci.

If you would like to contribute:

  • Fork the repository.
  • Push your changes with passing specs.
  • Send us a pull request.

I'm very eager to keep this gem lightweight and on topic. If you're unsure whether a change would make it into the gem, talk to me beforehand.

Credits

Tobias Kraze from makandra

Henning Koch from makandra

active_type's People

Contributors

anthonyjsmith avatar atcruice avatar biow0lf avatar chriscz avatar d-m-u avatar dastra-mak avatar denzelem avatar dlackty avatar fleinzi avatar foobear avatar fsateler avatar judithroth avatar kdiogenes avatar kraatob avatar kratob avatar lcmen avatar martinschaflitzl1 avatar mattbrictson avatar maximilianogarciaroe avatar nalabjp avatar nhasselmeyer avatar niklashae avatar petergoldstein avatar rriksma avatar snow avatar sudoremo avatar tom-kuca avatar triskweline avatar unrooty-infinum avatar zetavg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

active_type's Issues

Since 0.6.3 version it changes the way to Casting records or relations

In the Readme say than the way to do "Casting records or relations" is using: ActiveType.cast

But in 0.6.3 version rise the next error:

undefined method `Util' for ActiveType:Module

I think the documentation sample should be change to:

class User < ActiveRecord::Base
  ...
end

class SignUp < ActiveType::Record[User]
  ...
end

user = User.find(1)
sign_up = ActiveType::Util.cast(user, SignUp)
sign_up.is_a?(SignUp) # => true

Helper Convenience Method

Draper uses a convenience method #h to invoke a view helper. It would be great if ActiveType used the same convention. IMHO prefixing with #h is better than directly including the large number of methods in ActionController::Base.helpers.

module ActiveType
  module Helpers
    def h
      ActionController::Base.helpers
    end
  end
end

h.puralize(2, "word") 

Comparing to ActiveModel?

I'm curious what's the difference between this project and ActiveModel that ships with Rails?

You can create tableless models using ActiveModel since Rails 3:

class Person
  include ActiveModel::Model

  attr_accessor :username

  validates :username, presence: true
end

The validation, callback, and AR logic not tied to a DB has been refactored out of AR (around Rails 3 I think) for exactly this type of problem.

NoMethodError with Rails 4.2.0.beta1

When accessing an attribute using Rails 4.2.0.beta1, I get a NoMethodError

class Test < ActiveType::Object
  attribute :a_value, :string
end

Test.new.value

NoMethodError: super: no superclass method `type_cast' for #<ActiveType::VirtualAttributes::VirtualColumn:0x007f9e57efac48>
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/active_type-0.2.1/lib/active_type/virtual_attributes.rb:44:in `type_cast'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/active_type-0.2.1/lib/active_type/virtual_attributes.rb:165:in `read_virtual_attribute'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/active_type-0.2.1/lib/active_type/virtual_attributes.rb:79:in `a_value'
    from (irb):10
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/railties-4.2.0.beta1/lib/rails/commands/console.rb:110:in `start'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/railties-4.2.0.beta1/lib/rails/commands/console.rb:9:in `start'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/railties-4.2.0.beta1/lib/rails/commands/commands_tasks.rb:68:in `console'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/railties-4.2.0.beta1/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/railties-4.2.0.beta1/lib/rails/commands.rb:17:in `<top (required)>'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0.beta1/lib/active_support/dependencies.rb:248:in `require'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0.beta1/lib/active_support/dependencies.rb:248:in `block in require'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0.beta1/lib/active_support/dependencies.rb:233:in `load_dependency'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0.beta1/lib/active_support/dependencies.rb:248:in `require'
    from /Users/herman/Projects/ttt/bin/rails:8:in `<top (required)>'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0.beta1/lib/active_support/dependencies.rb:242:in `load'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0.beta1/lib/active_support/dependencies.rb:242:in `block in load'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0.beta1/lib/active_support/dependencies.rb:233:in `load_dependency'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0.beta1/lib/active_support/dependencies.rb:242:in `load'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/spring-1.1.3/lib/spring/commands/rails.rb:6:in `call'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/spring-1.1.3/lib/spring/command_wrapper.rb:38:in `call'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/spring-1.1.3/lib/spring/application.rb:180:in `block in serve'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/spring-1.1.3/lib/spring/application.rb:153:in `fork'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/spring-1.1.3/lib/spring/application.rb:153:in `serve'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/spring-1.1.3/lib/spring/application.rb:128:in `block in run'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/spring-1.1.3/lib/spring/application.rb:122:in `loop'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/spring-1.1.3/lib/spring/application.rb:122:in `run'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/spring-1.1.3/lib/spring/application/boot.rb:18:in `<top (required)>'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
    from /Users/herman/.rbenv/versions/2.1.2/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
    from -e:1:in `<main>'

Best Practices for ActionMailer ?

I've been using the "Growing Rails Application" technique, and my controllers, models, views and tests are cleaner and easier to navigate than ever.

But my mailers - not so much. The app/mailers directory is good. But the mail templates are scattered across many subdirectories in app/views. I've got dozens of mailer templates, and it is easy to lose track of things.

I've organized all my mailer templates under a single directory app/mailers/templates using default template_path: "../mailers/templates/#{self.name.underscore}" in my mailer classes. That helps.

I'm curious if there is a better way. Does anyone have any tips for organizing mailers and their associated templates?

(PS - if there a better place for me to post "Growing Rails Application" related questions, let me know...)

new_record? is not correct when model save callback raise an exception

Rails 5.0.0.1

Model

class User < ActiveType::Object
  attribute :name
  validates_presence_of :name

  save do
    raise ActiveRecord::Rollback
  end

end

Console

pry(main)> user = User.new
=> #<User name: nil>
pry(main)> user.new_record?
=> true
pry(main)> user.save
=> false
pry(main)> user.new_record?
=> true
pry(main)> user.name = 'sunny'
=> "sunny"
pry(main)> user.save
   (0.2ms)  BEGIN
   (0.2ms)  ROLLBACK
=> true
pry(main)> user.new_record?
=> false

Issue

The user.new_record? should be true when save callback raise an exception.

Rails 4.2.0: Array/Hash typecast

  attribute :product_bindings, :hash, default: proc { Hash.new }

Raises the error:

ERROR:  syntax error at or near "array"
LINE 1: SELECT 'array'::regtype::oid
               ^
CONTEXT:  invalid type name "array"

Boolean typecast is

ActiveRecord converts string values of "false" and "true" to false and true for boolean fields in models.

ActiveType on the other hand assigns 0 to boolean field, in any case, which is not correct either, after all strings are considered truthy in Ruby.

I believe booleans should contain true or false instead of 0 and 1.

Type-casting behaviour is something I can live with, but I would like to hear you comments what do you think is the best course of action. I am parsing these values from XML so they are coming up as strings. As of now I am probably going to change ActiveType attribute to string and then pass to ActiveRecord as is.

Using `attribute` class macro with specific class as the type

After bumping to Rails 4.2, my code here:

module Flyblade::GiftCard
  class CreditCard < ActiveType::Object
    attribute :cvc,            :varchar
    attribute :user,           Flyblade::GiftCard::User
  end
end

... now generates the following error/server output:

Started GET "/gift_cards/new" for ::1 at 2014-12-24 11:12:33 -0500
Processing by GiftCardsController#new as HTML
D, [2014-12-24T11:12:34.086022 #28239] DEBUG -- :   User Load (0.5ms)  SELECT  "users".* FROM "users" WHERE "users"."id
" = $1  ORDER BY "users"."id" ASC LIMIT 1  [["id", 9477]]
E, [2014-12-24T11:12:34.113763 #28239] ERROR -- : PG::SyntaxError: ERROR:  syntax error at or near "User"
LINE 1: SELECT 'Flyblade::GiftCard::User'::regtype::oid
               ^
CONTEXT:  invalid type name "Flyblade::GiftCard::User"
: SELECT 'Flyblade::GiftCard::User'::regtype::oid
Completed 500 Internal Server Error in 37ms
** [Bugsnag] No API key configured, couldn't notify

PG::SyntaxError - ERROR:  syntax error at or near "User"
LINE 1: SELECT 'Flyblade::GiftCard::User'::regtype::oid
               ^
CONTEXT:  invalid type name "Flyblade::GiftCard::User"

Any ideas @henning-koch? If you can point me in the direction of the potential break I'd be happy to look into the source code.

ERROR: type "string" does not exist

PG::UndefinedObject - ERROR: type "string" does not exist

Anybody getting the above error should use :varchar or :text instead of :string. Eg.

class SignIn < ActiveType::Object
    attribute :email_id, :varchar
    attribute :password, :varchar
    attribute :remember_me, :boolean

Basically you need to stick to DBMS' datatype. Since postgres doesn't understand "string", it throws error.

Rails 4: after_commit callbacks do not work for ActiveType::Object

When ActiveType::Object is used in Rails 4, before_save and after_save callbacks are executed as expected, but after_commit is not. This used to work in Rails 3.2.

  • active_type (0.4.0)
  • pg (0.18.2)

Trivial example:

class Hello < ActiveType::Object
  after_commit :say_hi

  private

  def say_hi
    puts "Hi!"
  end
end

When this model is saved, the say_hi method is never executed.

$ rails c 
Loading development environment (Rails 4.0.13)
>> h = Hello.new
=> #<Hello >
>> h.save!
   (0.1ms)  BEGIN
   (0.1ms)  COMMIT
=> true
>> 

Dup is not duplicating the virtual attributes of an object

When you are calling dup or clone to an ActiveType object a new instance of the object is created but the virtual attributes of the new instance are linked to the original instance.

Eg:

orig = MyObject.new(title: 'orig_field')
copy = orig.dup
copy.title = 'new_field'
orig.title #=> new_field

I don't know if it's by design or it's anissue. Maybe there are other workarounds to clone an ActiveType object that I am missing.

Many thanks in advance.

what is a proper way to override attribute?

I have a form where field - ActiveType attribute password - value may come empty
so what is a proper way to override attribute? or set default when attribute empty?
for now I am doing this and it works

  def password=(value)
    super
    write_virtual_attribute(:password, generate_password) if value.empty?
  end

I wonder is it good solution?

type cast on writing virtual attribute

I'm not sure if it's a bug.
Use code like this:

class CallSession < ActiveType::Object
  attribute :start_date, :datetime
end

def create_session
  Time.use_zone('UTC') { CallSession.new(start_date: '2016-02-24 10:46:43')}
end

Time.zone = 'Moscow'
session = create_session
session.start_date 
=> Wed, 24 Feb 2016 10:46:43 MSK +03:00

The problem is: when I assign value, attribute_writer only invalidate cache and set raw value, and actual type_caster runs only when I try to read value.
In this case moment when type_caster runs is important.

Nests_one vs. has_one

I have a regular ActiveRecord::Base model with has_one association, which has a defined class_name because the associated model is namespaced. Then I defined an ActiveType::Record with the original model and called nests_one with the associated model and defined scope (again with the fully namespaced class name of the associated model).

I can work with the ActiveType::Record just fine, but when I try to access the associated model I get nil even when it exists (doing the same for the underlying model works fine), there's no query in the log.

I've tried moving the has_one call around and it doesn't really matter where I put it or if it's there at all. Which leads me to assume, that ActiveType somehoew redefines the method for accessing the associated model by name but I didn't find any way to specify properties of the association by nests_one.

I would like to keep the association at the core model, because it is read in other contexts and is an integral part of the model. But I need the access via nested attributes only in one context (calling accepts_nested_attributes in the underlying model seems to work), which would lead me to using nests_one in the ActiveType::Record to indicate, that this type of manipulation is specific to that interface.

I assume, it's somehow my fault, but just can't figure out what am I doing wrong.

nests_zzz doesn't work for ActiveType::Record

Hi,

as stated above the nested attributes don't work with ActiveType::Record . The problem is in extended_record.rb . It simply doesn't include NestedAttributes (though ActiveType::Record does). Including it works for me but I don't know if this is intended at all. (I mailed Henning about this but got no reply yet).

time_select does not work with :datetime-attributes

Hi,
I have an issue where time_select does not work with :datetime-attributes. When passing the params to the initializer (such as {"start_time(1i)"=>"2015", "start_time(2i)"=>"2", "start_time(3i)"=>"11", "start_time(4i)"=>"16", ....), rails returns a ActiveRecord::MultiparameterAssignmentErrors-exception.

This one just masks another exception, which is triggered here: https://github.com/rails/rails/blob/3-2-stable/activerecord/lib/active_record/attribute_assignment.rb#L149

The expression (self.class.reflect_on_aggregation(name.to_sym) || column_for_attribute(name)) evaluates to nil, which blows up when klass is called on it.

I'm on rails 3.2.21 and active_type 0.3.3. Any idea?

All the best,
Fabian

Nested objects

Hi

I have a code like

class CompanyUpdate < ActiveType::Object
nests_one :comment,
            :build_scope => proc { Comment },
            :default => proc { Comment.new(:text => 'holla') }
end

As far as I can see in the builder class the comment attribute is created. But an assignment doesn't call the assign_attributes method. So if I do

CompanyUpdate.new(:comment => {:text => 'ok'}) 

assign_attributes is not called but with

CompanyUpdate.new(:comment_attributes => {:text => 'ok'}) 

it does work. My question is: Is this the way it should work or did I miss something in the docs.

THX

PG::UndefinedObject: ERROR: type "string" does not exist

Newbie to Ruby on Rails + Heroku Deployment .. not sure if this is issue is related to your Gem or with Heroku deployment environment. Works fine in my local (as I am not using PG)
Heroku environment details

  • ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]
  • Rails 4.2.3
  • pg (0.18.2)

and this is the model code

class Visitor < ActiveRecord::Base
    has_no_table
    column :email, :string
    validates_presence_of :email
    validates_format_of :email, :with => /\A[-a-z0-9_+\.]+\@([-a-z0-9]+\.)+[a-z0-9]{2,4}\z/i
    def subscribe
        mailchimp = Gibbon::API.new
        result = mailchimp.lists.subscribe({
            :id => ENV['MAILCHIMP_LIST_ID'],
            :email => {:email => self.email},
            :double_optin => false,
            :update_existing => true,
            :send_welcome => true
            })
        Rails.logger.info("Subscribed #{self.email} to MailChimp") if result
    end
end

below is the whole log dump

015-07-18T18:52:44.319347+00:00 app[web.1]:     from /app/config.ru:in `new'
2015-07-18T18:52:44.319350+00:00 app[web.1]:    from /app/config.ru:in `<main>'
2015-07-18T18:52:44.319353+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/builder.rb:49:in `eval'
2015-07-18T18:52:44.319357+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/builder.rb:49:in `new_from_string'
2015-07-18T18:52:44.319360+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/builder.rb:40:in `parse_file'
2015-07-18T18:52:44.319363+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/server.rb:299:in `build_app_and_options_from_config'
2015-07-18T18:52:44.319366+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/server.rb:208:in `app'
2015-07-18T18:52:44.319369+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/commands/server.rb:61:in `app'
2015-07-18T18:52:44.319372+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/server.rb:336:in `wrapped_app'
2015-07-18T18:52:44.319376+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/server.rb:272:in `start'
2015-07-18T18:52:44.319382+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/commands/server.rb:80:in `start'
2015-07-18T18:52:44.319385+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/commands/commands_tasks.rb:80:in `block in server'
2015-07-18T18:52:44.319389+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/commands/commands_tasks.rb:75:in `tap'
2015-07-18T18:52:44.319392+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/commands/commands_tasks.rb:75:in `server'
2015-07-18T18:52:44.319396+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
2015-07-18T18:52:44.319399+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/commands.rb:17:in `<top (required)>'
2015-07-18T18:52:44.319402+00:00 app[web.1]:    from bin/rails:8:in `require'
2015-07-18T18:52:44.319405+00:00 app[web.1]:    from bin/rails:8:in `<main>'
2015-07-18T18:52:45.246428+00:00 heroku[web.1]: Process exited with status 1
2015-07-18T18:52:45.262519+00:00 heroku[web.1]: State changed from starting to crashed
2015-07-18T18:52:45.263702+00:00 heroku[web.1]: State changed from crashed to starting
2015-07-18T18:52:49.560089+00:00 heroku[web.1]: Starting process with command `bin/rails server -p 52931 -e production`
2015-07-18T18:52:55.289443+00:00 app[web.1]: => Booting Thin
2015-07-18T18:52:55.289470+00:00 app[web.1]: => Rails 4.2.3 application starting in production on http://0.0.0.0:52931
2015-07-18T18:52:55.289473+00:00 app[web.1]: => Run `rails server -h` for more startup options
2015-07-18T18:52:55.289474+00:00 app[web.1]: => Ctrl-C to shutdown server
2015-07-18T18:52:55.289475+00:00 app[web.1]: PG::UndefinedObject: ERROR:  type "string" does not exist
2015-07-18T18:52:55.289477+00:00 app[web.1]: LINE 1: SELECT 'string'::regtype::oid
2015-07-18T18:52:55.289478+00:00 app[web.1]:                ^
2015-07-18T18:52:55.289480+00:00 app[web.1]: : SELECT 'string'::regtype::oid
2015-07-18T18:52:55.289533+00:00 app[web.1]: Exiting
2015-07-18T18:52:55.289602+00:00 app[web.1]: /app/vendor/bundle/ruby/2.2.0/gems/activerecord-4.2.3/lib/active_record/connection_adapters/postgresql/database_statements.rb:155:in `async_exec': PG::UndefinedObject: ERROR:  type "string" does not exist (ActiveRecord::StatementInvalid)
2015-07-18T18:52:55.289604+00:00 app[web.1]: LINE 1: SELECT 'string'::regtype::oid
2015-07-18T18:52:55.289605+00:00 app[web.1]:                ^
2015-07-18T18:52:55.289609+00:00 app[web.1]: : SELECT 'string'::regtype::oid
2015-07-18T18:52:55.289611+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/activerecord-4.2.3/lib/active_record/connection_adapters/postgresql/database_statements.rb:155:in `block in execute'
2015-07-18T18:52:55.289613+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/activerecord-4.2.3/lib/active_record/connection_adapters/abstract_adapter.rb:473:in `block in log'
2015-07-18T18:52:55.289616+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.3/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
2015-07-18T18:52:55.289618+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/activerecord-4.2.3/lib/active_record/connection_adapters/abstract_adapter.rb:467:in `log'
2015-07-18T18:52:55.289621+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/activerecord-4.2.3/lib/active_record/connection_adapters/postgresql/database_statements.rb:154:in `execute'
2015-07-18T18:52:55.289625+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/activerecord-4.2.3/lib/active_record/connection_adapters/postgresql_adapter.rb:393:in `lookup_cast_type'
2015-07-18T18:52:55.289631+00:00 app[web.1]:    from /app/app/models/contact.rb:4:in `<class:Contact>'
2015-07-18T18:52:55.289628+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/bundler/gems/activerecord-tableless-800393c52bd2/lib/activerecord-tableless.rb:93:in `column'
2015-07-18T18:52:55.289634+00:00 app[web.1]:    from /app/app/models/contact.rb:1:in `<top (required)>'
2015-07-18T18:52:55.289638+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.3/lib/active_support/dependencies.rb:274:in `require'
2015-07-18T18:52:55.289641+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.3/lib/active_support/dependencies.rb:274:in `block in require'
2015-07-18T18:52:55.289648+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.3/lib/active_support/dependencies.rb:274:in `require'
2015-07-18T18:52:55.289645+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.3/lib/active_support/dependencies.rb:240:in `load_dependency'
2015-07-18T18:52:55.289654+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.3/lib/active_support/dependencies.rb:317:in `depend_on'
2015-07-18T18:52:55.289651+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.3/lib/active_support/dependencies.rb:360:in `require_or_load'
2015-07-18T18:52:55.289657+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.3/lib/active_support/dependencies.rb:233:in `require_dependency'
2015-07-18T18:52:55.289661+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/engine.rb:472:in `block (2 levels) in eager_load!'
2015-07-18T18:52:55.289664+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/engine.rb:471:in `each'
2015-07-18T18:52:55.289675+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/engine.rb:469:in `eager_load!'
2015-07-18T18:52:55.289668+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/engine.rb:471:in `block in eager_load!'
2015-07-18T18:52:55.289683+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/application/finisher.rb:56:in `block in <module:Finisher>'
2015-07-18T18:52:55.289679+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/application/finisher.rb:56:in `each'
2015-07-18T18:52:55.289686+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/initializable.rb:30:in `instance_exec'
2015-07-18T18:52:55.289671+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/engine.rb:469:in `each'
2015-07-18T18:52:55.289678+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/engine.rb:346:in `eager_load!'
2015-07-18T18:52:55.289696+00:00 app[web.1]:    from /app/vendor/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:226:in `block in tsort_each'
2015-07-18T18:52:55.289689+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/initializable.rb:30:in `run'
2015-07-18T18:52:55.289702+00:00 app[web.1]:    from /app/vendor/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:429:in `each_strongly_connected_component_from'
2015-07-18T18:52:55.289692+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/initializable.rb:55:in `block in run_initializers'
2015-07-18T18:52:55.289706+00:00 app[web.1]:    from /app/vendor/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:347:in `block in each_strongly_connected_component'
2015-07-18T18:52:55.289699+00:00 app[web.1]:    from /app/vendor/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:348:in `block (2 levels) in each_strongly_connected_component'
2015-07-18T18:52:55.289721+00:00 app[web.1]:    from /app/vendor/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:203:in `tsort_each'
2015-07-18T18:52:55.289729+00:00 app[web.1]:    from /app/config/environment.rb:5:in `<top (required)>'
2015-07-18T18:52:55.289708+00:00 app[web.1]:    from /app/vendor/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:345:in `each'
2015-07-18T18:52:55.289723+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/initializable.rb:54:in `run_initializers'
2015-07-18T18:52:55.289732+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.3/lib/active_support/dependencies.rb:274:in `require'
2015-07-18T18:52:55.289711+00:00 app[web.1]:    from /app/vendor/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:345:in `call'
2015-07-18T18:52:55.289714+00:00 app[web.1]:    from /app/vendor/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:345:in `each_strongly_connected_component'
2015-07-18T18:52:55.289726+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/application.rb:352:in `initialize!'
2015-07-18T18:52:55.289718+00:00 app[web.1]:    from /app/vendor/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:224:in `tsort_each'
2015-07-18T18:52:55.289735+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.3/lib/active_support/dependencies.rb:274:in `block in require'
2015-07-18T18:52:55.289738+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.3/lib/active_support/dependencies.rb:240:in `load_dependency'
2015-07-18T18:52:55.289741+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.3/lib/active_support/dependencies.rb:274:in `require'
2015-07-18T18:52:55.289748+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/builder.rb:55:in `instance_eval'
2015-07-18T18:52:55.289751+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/builder.rb:55:in `initialize'
2015-07-18T18:52:55.289745+00:00 app[web.1]:    from /app/config.ru:3:in `block in <main>'
2015-07-18T18:52:55.289754+00:00 app[web.1]:    from /app/config.ru:in `new'
2015-07-18T18:52:55.289774+00:00 app[web.1]:    from /app/config.ru:in `<main>'
2015-07-18T18:52:55.289776+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/builder.rb:49:in `eval'
2015-07-18T18:52:55.289780+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/builder.rb:49:in `new_from_string'
2015-07-18T18:52:55.289781+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/builder.rb:40:in `parse_file'
2015-07-18T18:52:55.289783+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/server.rb:299:in `build_app_and_options_from_config'
2015-07-18T18:52:55.289787+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/server.rb:208:in `app'
2015-07-18T18:52:55.289790+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/commands/server.rb:61:in `app'
2015-07-18T18:52:55.289792+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/server.rb:336:in `wrapped_app'
2015-07-18T18:52:55.289795+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/server.rb:272:in `start'
2015-07-18T18:52:55.289798+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/commands/server.rb:80:in `start'
2015-07-18T18:52:55.289801+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/commands/commands_tasks.rb:80:in `block in server'
2015-07-18T18:52:55.289804+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/commands/commands_tasks.rb:75:in `tap'
2015-07-18T18:52:55.289808+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/commands/commands_tasks.rb:75:in `server'
2015-07-18T18:52:55.289811+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
2015-07-18T18:52:55.289814+00:00 app[web.1]:    from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.3/lib/rails/commands.rb:17:in `<top (required)>'
2015-07-18T18:52:55.289817+00:00 app[web.1]:    from bin/rails:8:in `require'
2015-07-18T18:52:55.289820+00:00 app[web.1]:    from bin/rails:8:in `<main>'
2015-07-18T18:52:56.648562+00:00 heroku[web.1]: Process exited with status 1
2015-07-18T18:52:56.673206+00:00 heroku[web.1]: State changed from starting to crashed

Association writer method name

This somewhat goes along with this issue. Basically, I want my public api to allow for something like this:

class ParentForm < ActiveType::Record[Parent]
  attribute :whatever
  nests_many :children, scope: -> {ChildForm}
end
class ChildForm < ActiveType::Record[Child]
  validates :name, presence: true
end

Such that when I create a parent form, I could pass in an object like this:

{
  whatever: "something",
  children: [
    {name: 'one'},
    {name: 'two'}
  ]
}

And I'd have the children array all casted to ChildForm objects. Basically what I want is to NOT enforce the _attributes suffix on a nested child writer key.

I can see from the code that this currently isn't possible, but I'm looking for advice on how to achieve this.

I don't like the _attributes= prefix requirement as I don't really think a public API endpoint should need to be aligned with the html form that might be used in conjunction with it. For a public API perspective, I just want to pass in children, not children_attributes.

Any suggestions?

Sidekiq throws 'Active Record Unknown Primary Key Error' on Active Type object

[Copied from here]

I am using the Sidekiq gem in my Rails app to handle some long-running processes asynchronously. As illustrated in this Railscast, a reference to the model to be processed is passed as an argument to the perform_async method of the worker class doing the background processing.

This would not be a problem if the model in question was an Active Record object. However it is an Active Type object designed to "quack like ActiveRecord" and unfortunately it does not quack as loudly so I get an ActiveRecord::UnknownPrimaryKeyError.

How do I set a primary key for a Ruby object that really is not a db object and convince Sidekiq to treat it as such? Unable to glean information on how to do this from the Active Type Github page.

Any help will be greatly appreciated!

incompatible with rails-5.0.0.beta2

The following code

class UserSession < ActiveType::Object
end

UserSession.new

generated

ActiveRecord::StatementInvalid: Could not find table 'objects'

error.

PG type "hash" does not exist

ActiveRecord::StatementInvalid: PG::UndefinedObject: ERROR:  type "hash" does not exist
LINE 1: SELECT 'hash'::regtype::oid

With Rails 4.2:

  attribute :product_bindings  , :hash    , default: proc { Hash.new }

How to make existing nested records read_only?

I'm having some trouble figuring out how to implement the following business logic with nests_one (or with accepts_nested_attributes_for using plain activerecord):

An Order has an Organization. When creating an order, the user can fill out organization attributes, two of which are nickname & email. However, if either nickname or matches an existing organization it should be attached to order, but not edited, which I wish to enforce in the model.

Similarly, the Organization has a Contact, with natural primary key email.

Is there a clean way to build this up with the existing ActiveType api using nests_one, or would I be better off just to use attribute organization_attrs etc. and implement the logic in the AR callbacks?

To sum it up: how do I make nested attributes act as find-or-create rather than find-and-update-or-create?

ActiveRecord.becomes solution for Rails4

In #12, @henning-koch posted this snippet for an ActiveRecord#becomes method:

ActiveRecord::Base.class_eval do
  def self.becomes(other_class)
    other_class.scoped.merge(scoped)
  end
end

Sadly, #scoped was removed in Rails4, and the proposed replacement #all doesn't work when running in the scope of an abstract parent. (It returns the parent relation instead of the child relation).

Here is a snippet for a #becomes method that should work with both Rails3 and Rails4.

ActiveRecord::Base.class_eval do
  class << self
    def becomes(new_klass)
      if Rails.version.match(/^4/)
        child_relation(new_klass).merge(all)
      else
        new_klass.scoped.merge(scoped)       # Rails 3 syntax from @henning
      end
    end

    private

    def child_relation(new_klass)
      original_value, self.abstract_class = [self.abstract_class, true]
      relation = new_klass.all
      self.abstract_class = original_value
      relation
    end
  end
end

Here's an example of how to use the #becomes method:

class Team << ActiveRecord::Base
  has_many :abstract_members
end
class AbstractMember << ActiveRecord::Base
  belongs_to :team
end
class Member << AbstractMember
end

AbstractMember.where(<condition>).becomes(Member).first.class   #=> Member
Team.find(<N>).abstract_members.becomes(Member).first.class     #=> Member

Table doesn't exist Error

When I add the gem to a brand new project and then try ActiveType::Object.new in the rails console, it gives me the following error:

Table doesn't exist Error

ruby '2.0.0'
gem 'rails', '4.0.0'

Changelog?

It would be great to review a list of changes before upgrading to the latest version of ActiveType.

Could you add a changelog?

Broken behavior with boolean attributes in rails 4.2

After upgrade to rails 4.2, boolean attributes seem to be broken. Even if I do not check a checkbox, it is always interpreted as a "true" value. For instance, this validation always passes:

class AgreeForm < ActiveType::Object
....
attribute :agree, :boolean
validates :agree, :presence => true
end

Any clue?

Record instance variables uninitialized after find

I have a MyForm < ActiveType::Record[Person], and when I do

f = MyForm.find(some_id)
f.attr = 'abc'
f.save

I get a

NoMethodError: undefined method `[]' for nil:NilClass
    from /home/joconnor/.rvm/gems/jruby-1.7.9@xpesa/gems/active_type-0.1.2/lib/active_type/virtual_attributes.rb:128:in `read_virtual_attribute'
    from /home/joconnor/.rvm/gems/jruby-1.7.9@xpesa/gems/active_type-0.1.2/lib/active_type/virtual_attributes.rb:73:in `third_party_account_nr'
    from /home/joconnor/.rvm/gems/jruby-1.7.9@xpesa/gems/activemodel-3.2.14/lib/active_model/validator.rb:151:in `validate'
    from org/jruby/RubyArray.java:1613:in `each'
    from /home/joconnor/.rvm/gems/jruby-1.7.9@xpesa/gems/activemodel-3.2.14/lib/active_model/validator.rb:150:in `validate'

My workaround is to add an after_initialize method to MyForm:

def init_virtual_fields
   @virtual_attributes ||= {}
   @virtual_attributes_cache ||= {}
end

A better solution would be to use accessor methods for @virtual_attributes and @virtual_attributes_cache:

def virtual_attributes
  @virtual_attributes ||= {}
end

def virtual_attributes_cache
  @virtual_attributes_cache ||= {}
end

PS: I loved your book: Growing Rails Applications in Practice

belongs_to association not loaded with rails 4.2.1

unless File.exist?('Gemfile')
  File.write('Gemfile', <<-GEMFILE)
    source 'https://rubygems.org'
    gem 'rails', 4.2.1.rc2
    gem 'sqlite3'
    gem 'active_type', '0.3.3'
  GEMFILE

  system 'bundle'
end
require 'bundler'
Bundler.setup(:default)
require 'active_type'
require 'active_record'
require 'minitest/autorun'
require 'logger'
Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test)
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
ActiveRecord::Base.logger = Logger.new(STDOUT)

ActiveRecord::Schema.define do
  create_table :posts, force: true do |t|
  end

  create_table :comments, force: true do |t|
    t.integer :post_id
  end
end

class Post < ActiveRecord::Base
end

class CommentObj < ActiveType::Object
  belongs_to :post
  attribute :post_id, :integer
end

class Comment < ActiveRecord::Base
  belongs_to :post
end

class BugTest < Minitest::Test
  def test_association_stuff
    post = Post.create!
    comment_obj = CommentObj.new post_id:post.id
    comment = Comment.new post_id:post.id

    assert_equal post, comment.post
    assert_equal post, comment_obj.post
  end
end

The line assert_equal post, comment_obj.post fails. Seems to work with 4.2.0.

Allow to change an association's model

I'd like to create associations that return ActiveType objects - something like the example below:

class User < ActiveRecord::Base
  has_many :messages
end
class Message < ActiveRecord::Base
  belongs_to :user
end
class User::AsTexting < ActiveType::Record[User]
  has_many :texting_messages, class_name: 'Message::AsTexting'
end
class Message::AsTexting < ActiveType::Record[Message]
  belongs_to :texting_user, class_name: 'User::AsTexting'
end

Will this work? Is there a better way to build Rails-like associations to ActiveType objects?

ActiveType don't play well with refile

Following the instructions in https://github.com/refile/refile#pure-ruby-classes I write the following class:

class Files < ActiveType::Object
  extend Refile::Attachment

  attr_accessor :docs_id
  attr_accessor :activity_id

  attachment :docs
  attachment :activity
end

When I do:

f = Files.new
f.docs = StringIO.new('teste')

I get the following error:

NoMethodError: undefined method `docs_id_will_change!' for #<Files >
from /home/kadu/.rvm/gems/ruby-2.2.1@fnix/gems/activemodel-4.2.1/lib/active_model/attribute_methods.rb:433:in `method_missing'

If I make my class Pure, remove the ActiveType::Object inheritance, it's work. I don't have success while trying to understand why this is happening.

Calling #klass on ActiveObject attributes returns nil

Hello!

My ActiveObject model contains an attributes of type DateTime.
This attributes is populated by a datetime_select field.

When trying to assign the attribute, Rails raises a MultiparamterAssignmentErrors exception.
The exception is due to Rails calling Model.attribute.klass to determine how to assign the attribute.
However, this call returns an error, undefined method klass for nil:NilClass.

Do you have an idea on how to resolve this issue?

Thanks.

Can't run specs for Gemfile.3.2.mysql2: CREATE TABLE invalid statement

I am trying to run the specs as instructed in the README using rake all:spec.

All specs for all gemfiles pass, with the exception of Gemfile.3.2.mysql2. I get an ActiveRecord::StatementInvalid error when spec/support/database.rb is trying to create the tables in the database:

All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead:
CREATE TABLE `records` (
  `id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, 
  `persisted_string` varchar(255), 
  `persisted_integer` int(11), 
  `persisted_time` datetime,  
  `persisted_date` date, 
  `persisted_boolean` tinyint(1)
) ENGINE=InnoDB

Again, this works fine for sqlite, pg, and for Gemfile.4.2.1.mysql2. It is only Gemfile.3.2.mysql2 that has the problem. Any ideas?

Full backtrace:

rake all:spec

gemfiles/Gemfile.3.2.mysql2

-- create_table(:records)
/Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-3.2.22/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:245:in `query': Mysql2::Error: All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead: CREATE TABLE `records` (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `persisted_string` varchar(255), `persisted_integer` int(11), `persisted_time` datetime, `persisted_date` date, `persisted_boolean` tinyint(1)) ENGINE=InnoDB (ActiveRecord::StatementInvalid)
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-3.2.22/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:245:in `block in execute'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-3.2.22/lib/active_record/connection_adapters/abstract_adapter.rb:280:in `block in log'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activesupport-3.2.22/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-3.2.22/lib/active_record/connection_adapters/abstract_adapter.rb:275:in `log'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-3.2.22/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:245:in `execute'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-3.2.22/lib/active_record/connection_adapters/mysql2_adapter.rb:213:in `execute'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-3.2.22/lib/active_record/connection_adapters/abstract/schema_statements.rb:170:in `create_table'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-3.2.22/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:434:in `create_table'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-3.2.22/lib/active_record/migration.rb:466:in `block in method_missing'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-3.2.22/lib/active_record/migration.rb:438:in `block in say_with_time'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/2.2.0/benchmark.rb:288:in `measure'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-3.2.22/lib/active_record/migration.rb:438:in `say_with_time'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-3.2.22/lib/active_record/migration.rb:458:in `method_missing'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-3.2.22/lib/active_record/migration.rb:334:in `method_missing'
    from /Users/mbrictson/Code/active_type/spec/support/database.rb:34:in `block in <top (required)>'
    from /Users/mbrictson/Code/active_type/spec/support/database.rb:32:in `class_eval'
    from /Users/mbrictson/Code/active_type/spec/support/database.rb:32:in `<top (required)>'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activesupport-3.2.22/lib/active_support/dependencies.rb:251:in `require'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activesupport-3.2.22/lib/active_support/dependencies.rb:251:in `block in require'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activesupport-3.2.22/lib/active_support/dependencies.rb:236:in `load_dependency'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activesupport-3.2.22/lib/active_support/dependencies.rb:251:in `require'
    from /Users/mbrictson/Code/active_type/spec/spec_helper.rb:9:in `block in <top (required)>'
    from /Users/mbrictson/Code/active_type/spec/spec_helper.rb:9:in `each'
    from /Users/mbrictson/Code/active_type/spec/spec_helper.rb:9:in `<top (required)>'
    from /Users/mbrictson/Code/active_type/spec/active_type/extended_record/single_table_inheritance_spec.rb:1:in `require'
    from /Users/mbrictson/Code/active_type/spec/active_type/extended_record/single_table_inheritance_spec.rb:1:in `<top (required)>'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rspec-core-2.14.8/lib/rspec/core/configuration.rb:896:in `load'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rspec-core-2.14.8/lib/rspec/core/configuration.rb:896:in `block in load_spec_files'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rspec-core-2.14.8/lib/rspec/core/configuration.rb:896:in `each'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rspec-core-2.14.8/lib/rspec/core/configuration.rb:896:in `load_spec_files'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rspec-core-2.14.8/lib/rspec/core/command_line.rb:22:in `run'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rspec-core-2.14.8/lib/rspec/core/runner.rb:80:in `run'
    from /Users/mbrictson/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rspec-core-2.14.8/lib/rspec/core/runner.rb:17:in `block in autorun'

ActiveRecord::StatementInvalid: Mysql2::Error: Table 'project_development.objects' doesn't exist: SHOW FULL FIELDS FROM `objects`

I add active_type to gemfiles and execute bundle install successfuly. But when I use it in controller or rails console,I got below error message:

ActiveRecord::StatementInvalid: Mysql2::Error: Table 'project_development.objects' doesn't exist: SHOW FULL FIELDS FROM `objects`

I don't known what happened, pls give me some hints! I use rails 5.0.0.beta4。the detail code:

# app/models/import_form.rb
class ImportForm < ActiveType::Object

  attribute :poi_type, :string
  attribute :name, :string

  validates :poi_type, presence: true
  validates :name, presence: true
end
# app/controllers/import_form_controller.rb
class ImportFormController < ApplicationController
  def import
    @data = ImportForm.new
  end
end

Rails 4.2.0 ActiveType::Object#save fails with ActiveModel::MissingAttributeError can't write unknown attribute ``

Update: this affects Rails 4.2.0 only. Rails 4.2.1 does not seem to be affected.

Scenario:

  • Class MyForm inherits from ActiveType::Object
  • @myform has validation errors
  • Controller calls @myform.save

Expectation:

  • @myform.save should return false, since the object is invalid

Bug:

Instead, I get this exception:

ActiveModel::MissingAttributeError can't write unknown attribute ``

Cause:

  1. When save is called and validation fails, ActiveRecord calls restore_transaction_record_state
  2. This in turn calls write_attribute(self.class.primary_key, restore_state[:id])
  3. But for an ActiveType::Object, primary_key is nil
  4. write_attribute doesn't expect a nil attribute name, so it blows up

Workaround:

I've worked around the bug by explicitly declaring a MyForm.primary_key. I'm not sure if this has other consequences, but it seems to work:

def self.primary_key
  :id
end

Here's the relevant stack trace:

ActiveModel::MissingAttributeError - can't write unknown attribute ``:
  activerecord (4.2.0) lib/active_record/attribute.rb:124:in `with_value_from_database'
  activerecord (4.2.0) lib/active_record/attribute_set.rb:39:in `write_from_user'
  activerecord (4.2.0) lib/active_record/attribute_methods/write.rb:74:in `write_attribute_with_type_cast'
  activerecord (4.2.0) lib/active_record/attribute_methods/write.rb:56:in `write_attribute'
  activerecord (4.2.0) lib/active_record/attribute_methods/dirty.rb:92:in `write_attribute'
  activerecord (4.2.0) lib/active_record/transactions.rb:393:in `restore_transaction_record_state'
  activerecord (4.2.0) lib/active_record/core.rb:514:in `update_attributes_from_transaction_state'
  activerecord (4.2.0) lib/active_record/core.rb:508:in `sync_with_transaction_state'
  activerecord (4.2.0) lib/active_record/persistence.rb:86:in `new_record?'
  activerecord (4.2.0) lib/active_record/persistence.rb:99:in `persisted?'
  actionview (4.2.0) lib/action_view/helpers/form_helper.rb:456:in `apply_form_for_options!'
  actionview (4.2.0) lib/action_view/helpers/form_helper.rb:434:in `form_for'

unnecessary repetition in generated SQL

require 'rails/all'
require 'active_type'

ActiveRecord::Base.establish_connection(
  adapter:  "mysql2",
  host:     "localhost",
  username: "root",
  password: "",
  database: "xxx"                     
)

class Company < ActiveRecord::Base
  has_many :employees
end

class Human < ActiveRecord::Base
end

class Employee < Human
end

class Engineer < ActiveType::Record[Employee]
end

class Manager < ActiveType::Record[Employee]
end

Employee.descendants.map(&:sti_name) 
# => ["Employee", "Employee", "Employee", "Employee"]

Company.first.employees.to_sql  
# => "SELECT `humans`.* FROM `humans` WHERE `humans`.`type` IN ('Employee', 'Employee', 'Employee', 'Employee', 'Employee') AND `humans`.`company_id` = 1"

Though the generated SQL works as expected, it still doesn't look good to me. Any suggestions?

Dynamic Association Type ?

In #11, we talked about creating hard-coded associations that return ActiveType objects. This approach works in situations where you know the expected type ahead of time.

The downside of this approach is that you are forced to create a chain of ActiveType classes, which can sometimes grow deep and hard to manage.

In many situations, I want to dynamically select the type of object to be returned from an association. It would be great if I could do something like this:

class User < ActiveRecord::Base
  has_many :messages
end
class Message < ActiveRecord::Base
  belongs_to :user
end
class User::AsTexting < ActiveType::Record[User]
  has_many :texting_messages, class_name: 'Message::AsTexting'
end
class Message::AsTexting < ActiveType::Record[Message]
  belongs_to :texting_user, class_name: 'User::AsTexting'
end
user = User.new
texting_messages = user.messages('AsTexting')  # returns a collection of Message::AsTexting

The idea I have is similar to single-table-inheritance. But instead of storing the class name in a type field, it would be passed as a method argument.

Has anyone done anything like this? Is this possible in Rails?

Can't find ActiveType::Object from rake tasks of Rails

This problem is reproduced with active_type 0.6.2, not with 0.6.1.

% ruby -v
ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-darwin16]

% rails -v
Rails 5.0.1

% rails new demo && cd demo
% echo "gem 'active_type'" >> Gemfile
% bundle install
% echo 'class X < ActiveType::Object; end' > app/models/x.rb
% echo 'task foo: [:environment] do; X; end' > lib/tasks/foo.rake
% bundle exec rake foo
/Users/ani/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/activesupport-5.0.1/lib/active_support/xml_mini.rb:51: warning: constant ::Fixnum is deprecated
/Users/ani/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/activesupport-5.0.1/lib/active_support/xml_mini.rb:52: warning: constant ::Bignum is deprecated
/Users/ani/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/activesupport-5.0.1/lib/active_support/core_ext/numeric/conversions.rb:138: warning: constant ::Fixnum is deprecated
rake aborted!
NameError: uninitialized constant ActiveType::Object
/private/var/tmp/demo/app/models/x.rb:1:in `<top (required)>'
/private/var/tmp/demo/lib/tasks/foo.rake:1:in `block in <top (required)>'
/Users/ani/.rbenv/versions/2.4.0/bin/bundle:22:in `load'
/Users/ani/.rbenv/versions/2.4.0/bin/bundle:22:in `<main>'
Tasks: TOP => foo
(See full trace by running task with --trace)

Add after_add and after_remove callbacks to nests_one and nests_many

I'm trying to watch attributes to see if they've changed. I've written a module that works with ActiveModel::Dirty to track the changes of ordinary attributes:

https://gist.github.com/84214a0d46653d74ca2e.git

This allows you to do stuff like this:

before_save do
   if some_attribute_changed?
       #....  do some stuff ....
   end
end

However, this does not work with nested models. I'm writing a service object that wraps up a lot of functionality into one ActiveType class. I want to watch a bunch of related models for changes.

With active record, it's possible to attach callbacks to associations (see http://anti-pattern.com/dirty-associations-with-activerecord). For instance:

has_and_belongs_to_many :buckets,
                          :after_add    => :make_dirty,
                          :after_remove => :make_dirty

If nests_one and nests_many supported these callbacks, I could modify my module to track changes on associations as well.

before_destroy not working

Hi! I have a problem with active_type 0.4.0.
before_destroy (also after_destroy) callback never called

class Membership < ActiveType::Object
  before_save { puts 'hello wonderful world' }
  before_destroy { puts 'goodbye cruel world' }
end
Membership.new.save 
# => hello wonderful world
# => true
Membership.new.destroy 
# => #<Membership:0x007fefda4456e8> {}

Wrong time because of timezone

Hi!

We have a problem with the gem converting times into the current timezone.

When passing "2015-03-02T08:23:18Z" as time, which already includes timezone: Z (UTC), the time is converted into a wrong time according the servers time-zone.

This happens inside the gem when conversion is performed for time types:

(Time.zone is set to Australia/Darwin)
2.1.0 :086 > ActiveSupport::TimeWithZone.new(nil, Time.zone, Time.parse("2015-03-02T08:23:18Z"))
=> Mon, 02 Mar 2015 08:23:18 ACST +09:30

If we pass UTC the output is correct. So the

2.1.0 :085 > ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone.new("UTC"), Time.parse("2015-03-02T08:23:18Z"))
=> Mon, 02 Mar 2015 08:23:18 UTC +00:00

Time.parse itself does the right thing, considering the Z.:

Time.parse("2015-03-02T08:23:18Z")
=> 2015-03-02 08:23:18 UTC

Any hints how to prevent this?

Best regards,
Wudu

Routes for nested models

Hi,

I’ve read the book over and over and love it! I’ve studied active type and the book but there is one thing that isn’t entirely clear to me that I believe is missing in the book. The book lacks examples of how to setup routing for various scenarios and I’d like to hear more about how you solved that part. Specifically interested in how to solve the following https://gist.github.com/mhenrixon/2bc135e65a0099b3fb87

It doesn’t really matter how I try I can’t make it work without Players::PlayerLocksController or player_player_lock_path etc. It’s a shame the book was released without this section. Care to shed some light on this?

I’d really like to avoid PlayersPlayerLock or player_player_lock_path but before I go mental I thought it best to ask you guys organizing your applications like this how you solve the Player::Lock type of model in a routing/controller scenario.

After casting an ActiveRecord instance to ActiveType::Record, instance#errors.add won't recognize attributes defined in ActiveType instance

class User < ActiveRecord::Base
end

class Users::ChangePassword < ActiveType::Record[User]
  attribute :old_password, :string
  validates :old_password, presence: true
end

u = User.find 1
form = ActiveType.cast u, Users::ChangePassword
form.update old_password: ''

will get "undefind method old_password", because form.errors's instance var @base is still u

I've fixed it in snow@cafe7ed
But when I ran the specs, find out it requires PgSQL.
It's 03:47+0800 now, I'm so tired and all I want is Vodka and sleep, so I will setup PgSQL, run the spec and create a PR some days later. Maybe in this weekend.

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.