Rails Model Without a Table

rails 4-- model with no table

Just because you're using Rails, it doesn't mean every model has to inherit from ActiveRecord::Base

In your situation, I'd simply do something along these lines:

# app/models/feed.rb
class Feed
def initialize(feed_id)
@feed_id = feed_id
end

def fetch
# ... put the web-service handling here
end

# encapsulate the rest of your feed processing / handling logic here
end

# app/controllers/feeds_controller.rb
class FeedsController < ActionController::Base
def show
@feed = Feed.new(params[:feed_id])
@feed.fetch

# render
end
end

Remember: it's Ruby on Rails, not just Rails. You can do a lot more than just ActiveRecord models.

How to create ActiveRecord tableless Model in Rails 5?

Finally I have decided to left that code and move on. But with time I think it should be rewritten to relational solution or use JSON field.

Rails 5

class TableLess
include ActiveModel::Validations
include ActiveModel::Conversion
include ActiveModel::Serialization
extend ActiveModel::Naming

class Error < StandardError;
end

module Type
class JSON < ActiveModel::Type::Value
def type
:json
end

private
def cast_value(value)
(value.class == String) ? ::JSON.parse(value) : value
end
end

class Symbol < ActiveModel::Type::Value
def type
:symbol
end

private
def cast_value(value)
(value.class == String || value.class == Symbol) ? value.to_s : nil
end
end
end

def initialize(attributes = {})
attributes = self.class.columns.map { |c| [c, nil] }.to_h.merge(attributes)
attributes.symbolize_keys.each do |name, value|
send("#{name}=", value)
end
end

def self.column(name, sql_type = :string, default = nil, null = true)
@@columns ||= {}
@@columns[self.name] ||= []
@@columns[self.name]<< name.to_sym
attr_reader name
caster = case sql_type
when :integer
ActiveModel::Type::Integer
when :string
ActiveModel::Type::String
when :float
ActiveModel::Type::Float
when :datetime
ActiveModel::Type::DateTime
when :boolean
ActiveModel::Type::Boolean
when :json
TableLess::Type::JSON
when :symbol
TableLess::Type::Symbol
when :none
ActiveModel::Type::Value
else
raise TableLess::Error.new('Type unknown')
end
define_column(name, caster, default, null)
end

def self.define_column(name, caster, default = nil, null = true)
define_method "#{name}=" do |value|
casted_value = caster.new.cast(value || default)
set_attribute_after_cast(name, casted_value)
end
end

def self.columns
@@columns[self.name]
end

def set_attribute_after_cast(name, casted_value)
instance_variable_set("@#{name}", casted_value)
end

def attributes
kv = self.class.columns.map {|key| [key, send(key)]}
kv.to_h
end

def persisted?
false
end

end

and example

class Machine < TableLess
column :foo, :integer
column :bar, :float
column :winamp, :boolean
end

ActiveRecord::Base Without Table

This is an approach I have used in the past:

In app/models/tableless.rb

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

# Override the save method to prevent exceptions.
def save(validate = true)
validate ? valid? : true
end
end

In app/models/foo.rb

class Foo < Tableless
column :bar, :string
validates_presence_of :bar
end

In script/console

Loading development environment (Rails 2.2.2)
>> foo = Foo.new
=> #<Foo bar: nil>
>> foo.valid?
=> false
>> foo.errors
=> #<ActiveRecord::Errors:0x235b270 @errors={"bar"=>["can't be blank"]}, @base=#<Foo bar: nil>>

Rails model without database

I think the blog post you are linking is the best way to go. I would only suggest moving the stubbed out methods into a module not to pollute your code.

Accessing join table (A table without model) in rails

There is no harm in creating a Model for a table in Rails. Though, if you wish to avoid it, you can use raw SQL queries for same.

sql = "SELECT * from posts where id = #{params[:id}"
result = ActiveRecord::Base.connection.execute(sql)
result.to_a

Ruby on Rails: models that do not have a table

Checkout the screencast by Ryan Bates that covers exactly this - Tableless Models.

http://railscasts.com/episodes/193-tableless-model

With this approach, your Model would still subclass ActiveRecord::Base but define the columns manually, which allows you to use ActiveRecord features such as validations, and associations without a database.

Rails association with tables without models

Your current scenario does require a model, although when you need to store data like categories e.g Sports(football,tennis,cricket,swimming,basketball,etc), you can store them as constants in your config->initializers->constant eg. SPORT_CATEGORIES = [["Football","football"],["Tennis","tennis"],etc], alternatively if you have more cols to store you can create a model then create the default rows as you would in a php .sql file but in ruby of course :) For example:

sport_categories = [
{:category => "football", :category_type => "manly" },
{:category => "Tennis", :category_type => "manly" },
etc
]

sport_categories.each do |attributes|
Model_name_here.find_or_initialize_by_category(attributes[:category]).tap do |p|
p.category_type = attributes[:category_type]
p.save!
end
end

Then you run rake db:seed.

Rails nested model conversion to and from database without its own table

Keep in mind that database adapters handle certain serialization tasks
for you. For instance: json and jsonb types in PostgreSQL will be
converted between JSON object/array syntax and Ruby Hash or Array
objects transparently. There is no need to use serialize in this case.

- api.rubyonrails.org

Don't use serialize with native JSON/JSONB columns. Its meant to be used with string columns as a poor-mans alternative.

What you are trying to do is really outside the scope of what ActiveRecord does - AR is built around a relational model where models correspond to tables. And you cannot expect that AR will have any provisions to unmarshal a JSONB column into anything but basic scalar types. And I would consider if what you are doing is really worth the effort vs actually creating a separate table for the relation.

You are on the right track with ActiveModel::Model which will give your model the same behaviour as a regular model, but you should take a look at how ActiveRecord handles nested attributes:

class Rule < ApplicationRecord
def conditions_attributes=(attributes)
attributes.each do |a|
# you would need to implement this method
unless RuleCondition.reject_attributes?(a)
self.conditions << RuleCondition.new(c)
end
end
end
end

You can possibly mimic the other aspects of an association by creating setters/getters.

But then again you could just create a rule_conditions table with JSONB column and a one to many or m2m association and spend your time actually being productive instead.



Related Topics



Leave a reply



Submit