ActiveRecord::Base Without Table

前端 未结 7 1443
灰色年华
灰色年华 2020-12-01 01:40

This came up a bit ago ( rails model attributes without corresponding column in db ) but it looks like the Rails plugin mentioned is not maintained ( http://agilewebdevelopm

相关标签:
7条回答
  • 2020-12-01 02:06

    This is a search form that presents an object called criteria that has a nested period object with beginning and end attributes.

    The action in the controller is really simple yet it loads values from nested objects on the form and re-renders the same values with error messages if necessary.

    Works on Rails 3.1.

    The model:

    class Criteria < ActiveRecord::Base
      class << self
    
        def column_defaults
          {}
        end
    
        def column_names
          []
        end
      end # of class methods
    
      attr_reader :period
    
      def initialize values
        values ||= {}
        @period = Period.new values[:period] || {}
        super values
      end
    
      def period_attributes
        @period
      end
      def period_attributes= new_values
        @period.attributes = new_values
      end
    end
    

    In the controller:

    def search
      @criteria = Criteria.new params[:criteria]
    end
    

    In the helper:

    def criteria_index_path ct, options = {}
      url_for :action => :search
    end
    

    In the view:

    <%= form_for @criteria do |form| %>
      <%= form.fields_for :period do |prf| %>
        <%= prf.text_field :beginning_as_text %>
        <%= prf.text_field :end_as_text %>
      <% end %>
      <%= form.submit "Search" %>
    <% end %>
    

    Produces the HTML:

    <form action="/admin/search" id="new_criteria" method="post">
      <input id="criteria_period_attributes_beginning_as_text" name="criteria[period_attributes][beginning_as_text]" type="text"> 
      <input id="criteria_period_attributes_end_as_text" name="criteria[period_attributes][end_as_text]" type="text">
    

    Note: The action attribute provided by the helper and the nested attributes naming format that makes it so simple for the controller to load all the values at once

    0 讨论(0)
  • 2020-12-01 02:10

    Just an addition to the accepted answer:

    Make your subclasses inherit the parent columns with:

    class FakeAR < ActiveRecord::Base
      def self.inherited(subclass)
        subclass.instance_variable_set("@columns", columns)
        super
      end
    
      def self.columns
        @columns ||= []
      end
    
      def self.column(name, sql_type = nil, default = nil, null = true)
        columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null)
      end
    
      # Overrides save to prevent exceptions.
      def save(validate = true)
        validate ? valid? : true
      end
    end
    
    0 讨论(0)
  • 2020-12-01 02:12

    There is the activerecord-tableless gem. It's a gem to create tableless ActiveRecord models, so it has support for validations, associations, types. It supports Active Record 2.3, 3.0, 3.2

    The recommended way to do it in Rails 3.x (using ActiveModel) has no support for associations nor types.

    0 讨论(0)
  • 2020-12-01 02:14

    Validations are simply a module within ActiveRecord. Have you tried mixing them into your non-ActiveRecord model?

    class MyModel
      include ActiveRecord::Validations
    
      # ...
    end
    
    0 讨论(0)
  • 2020-12-01 02:14

    I figure the more answers the better since this is one of the first results in google when searching for "rails 3.1 models without tables"

    I've implements the same thing without using ActiveRecord::Base while including the ActiveRecord::Validations

    The main goal was to get everything working in formtastic, and below I've included a sample payment that will not get saved anywhere but still has the ability to be validated using the validations we all know and love.

    class Payment
      include ActiveModel::Validations
      attr_accessor :cc_number, :payment_type, :exp_mm, :exp_yy, :card_security, :first_name, :last_name, :address_1, :address_2, :city, :state, :zip_code, :home_telephone, :email, :new_record
    
      validates_presence_of :cc_number, :payment_type, :exp_mm, :exp_yy, :card_security, :first_name, :last_name, :address_1, :address_2, :city, :state
    
      def initialize(options = {})
        if options.blank?
          new_record = true
        else
          new_record = false
        end
        options.each do |key, value|
          method_object = self.method((key + "=").to_sym)
          method_object.call(value)
        end
      end
    
      def new_record?
        return new_record
      end
    
      def to_key
      end
    
      def persisted?
        return false
      end
    end
    

    I hope this helps someone as I've spent a few hours trying to figure this out today.

    0 讨论(0)
  • 2020-12-01 02:19

    UPDATE: For Rails 3 this can be done very easy. In Rails 3+ you can use the new ActiveModel module and its submodules. This should work now:

    class Tableless
      include ActiveModel::Validations
    
      attr_accessor :name
    
      validates_presence_of :name
    end
    

    For more info, you can check out the Railscast (or read about it on AsciiCasts) on the topic, as well as this blog post by Yehuda Katz.

    OLD ANSWER FOLLOWS:

    You may need to add this to the solution, proposed by John Topley in the previous comment:

    class Tableless
    
      class << self
        def table_name
          self.name.tableize
        end
      end
    
    end
    
    class Foo < Tableless; end
    Foo.table_name # will return "foos"
    

    This provides you with a "fake" table name, if you need one. Without this method, Foo::table_name will evaluate to "tablelesses".

    0 讨论(0)
提交回复
热议问题