问题
Looks like this method doesn't work anymore in rails 3.1. So, does someone have a working solution?
Actually, I've found this gist. It solves problems with columns_hash and column_defaults errors from the railscast's solution but I get ActiveRecord::ConnectionNotEstablished error all the time when I try to write some attribute.
Any thoughts?
回答1:
You should create your own model class and mix in the parts of ActiveModel (for example, validations) that you require. This blog post from Yehuda Katz has the details.
回答2:
The simplest tableless model in Rails 3.1 is:
class Session
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :email, :password
validates :email, :presence => true
validates :password, :presence => true
def initialize(attributes = {})
if attributes
attributes.each do |name, value|
send("#{name}=", value)
end
end
end
def persisted?
false
end
end
The ActiveModel::Validations is optional (only if validations are used). Also the constructor is not required (but highly desireable).
回答3:
For Rails / ActiveRecord 5.0 you need to redefine private def self.load_schema! to avoid checking the table_name. Also, notice a little hack for the column method (Type).
Here's the complete listing for Tableless model for Rails 5.0 / ActiveRecord 5.0
class Tableless < ActiveRecord::Base
def self.columns
@columns ||= []
end
def self.column(name, sql_type = nil, default = nil, null = true)
type = "ActiveRecord::Type::#{sql_type.to_s.camelize}".constantize.new
columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, type, null, '')
end
def self.columns_hash
@columns_hash ||= Hash[columns.map { |column| [column.name, column] }]
end
def self.column_names
@column_names ||= columns.map { |column| column.name }
end
def self.column_defaults
@column_defaults ||= columns.map { |column| [column.name, nil] }.inject({}) { |m, e| m[e[0]] = e[1]; m }
end
# Override the save method to prevent exceptions.
def save(validate = true)
validate ? valid? : true
end
private
def self.load_schema!
columns_hash.each do |name, column|
self.define_attribute(
name,
column.sql_type_metadata,
default: column.default,
user_provided_default: false
)
end
end
end
回答4:
This tableless thing seems more and more sort of a hack, but the mix just isn't the same thing (don't remember exactly what didn't work now, I've dealt with it some months ago, returned to it because upgrade to 3.1 broke it). The 3.1.0rc4 version worked with 'columns_hash' method override, the 3.1.0 requires also a 'column_defaults' override. So here's a version that passes my project tests.
class Tableless < ActiveRecord::Base
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
def self.columns_hash
@columns_hash ||= Hash[columns.map { |column| [column.name, column] }]
end
def self.column_names
@column_names ||= columns.map { |column| column.name }
end
def self.column_defaults
@column_defaults ||= columns.map { |column| [column.name, nil] }.inject({}) { |m, e| m[e[0]] = e[1]; m }
end
# Override the save method to prevent exceptions.
def save(validate = true)
validate ? valid? : true
end
end
Hope it works for you,
-- José
回答5:
For Rails 3.2 there is the activerecord-tableless gem. Its a gem to create tableless ActiveRecord models, so it has support for validations, associations, types.
When you are using the recommended way to do it in Rails 3.x there is no support for association nor types.
回答6:
and For Rails 3.2 the version of RUBY should be preferred 1.9.3 to avoid incompatibilities.
来源:https://stackoverflow.com/questions/7275496/tableless-model-in-rails-3-1