41

I want to create a select list for lets say colors, but dont want to create a table for the colors. I have seen it anywhere, but can't find it on google.

My question is: How can I put the colors in a model without a database table?

Or is there a better rails way for doing that?

I have seen someone putting an array or a hash directly in the model, but now I couldn't find it.

Arslan Ali
  • 17,418
  • 8
  • 58
  • 76
user993460
  • 821
  • 2
  • 8
  • 8

6 Answers6

66
class Model

  include ActiveModel::Validations
  include ActiveModel::Conversion
  extend ActiveModel::Naming

  attr_accessor :whatever

  validates :whatever, :presence => true

  def initialize(attributes = {})
    attributes.each do |name, value|
      send("#{name}=", value)
    end
  end

  def persisted?
    false
  end

end

attr_accessor will create your attributes and you will create the object with initialize() and set attributes.

The method persisted will tell there is no link with the database. You can find examples like this one: http://railscasts.com/episodes/219-active-model?language=en&view=asciicast

Which will explain you the logic.

Louis XIV
  • 2,224
  • 13
  • 16
28

The answers are fine for 2013 but since Rails 4 all the database independent features of ActiveRecord are extracted into ActiveModel. Also, there's an awesome official guide for it.

You can include as many of the modules as you want, or as little.

As an example, you just need to include ActiveModel::Model and you can forgo such an initialize method:

def initialize(attributes = {})
  attributes.each do |name, value|
    send("#{name}=", value)
  end
end

Just use:

attr_accessor :name, :age
Itay Grudev
  • 7,055
  • 4
  • 54
  • 86
Vedant Agarwala
  • 18,146
  • 4
  • 66
  • 89
  • 1
    Neat but it doesn't seem to allow `belongs_to`. I want to use `@filterModel.sector.name` and use the `sector_id` in the model. – Chloe Jun 06 '17 at 21:43
  • `include ActiveModel::Model` allows also to avoid the cancan `ArgumentError`: `cancancan (3.0.0) lib/cancan/controller_resource_builder.rb:8:in `initialize'` – iGian Apr 23 '19 at 15:22
  • Using ActiveModel is the right approach in 2022 – mthorley Mar 29 '22 at 19:16
11

The easiest answer is simply to not subclass from ActiveRecord::Base. Then you can just write your object code.

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
Scott S
  • 2,696
  • 16
  • 20
  • i dont need validation. all i need is an @colors variable with the colors, so i can put them in my select list form helper. – user993460 Jan 17 '13 at 22:22
  • 4
    Then the file color.rb will just have `def Color [some object code] end`. It just becomes a plain old object. – Scott S Jan 17 '13 at 22:25
  • Oh, sorry, I only saw half your comment. If thats really all you need, have you thought about using a constant? Assuming of course that you're just offering a static list of colors. Or perhaps even better, a partial with a select list with the colors you want available that you can just stick anywhere. – Scott S Jan 17 '13 at 22:27
  • ok, thanks. i will try it. but do you know what i mean with the model? i have seen it anywhere, but couldnt find it now. the guy created a model with an array or a hash and no table. – user993460 Jan 17 '13 at 22:29
  • 1
    I'm sorry, I don't think I'm understanding. Unless there is some other table-like behavior you're looking to keep, a Model without a table is just an Object. To add an array or hash is just a matter of adding it to the Object as either an instance or a class variable (which is explained here http://railstips.org/blog/archives/2006/11/18/class-and-instance-variables-in-ruby/) – Scott S Jan 17 '13 at 22:34
  • that article doesn't work for me using Rails 4.2 -- get `undefined method` errors on the first two lines `class_inheritable_accessor` and `self.columns` `for MyModel(Table doesn't exist):Class` – Don Cheadle Mar 02 '15 at 17:28
  • article linked to doesn't solve, at least for Rails 4.2. However the article links to *another* article which does help http://snipplr.com/view/1849/tableless-model/ – Don Cheadle Mar 02 '15 at 18:40
  • Article link is broken. – Michael Minter Jul 24 '16 at 03:08
6

What worked for me in Rails 6:

class MyClass
  include ActiveModel::Model

  attr_accessor :my_property
end
fguillen
  • 36,125
  • 23
  • 149
  • 210
2

If the reason you need a model without an associated table is to create an abstract class real models inherit from - ActiveRecord supports that:

class ModelBase < ActiveRecord::Base
  self.abstract_class = true
end
Itay Grudev
  • 7,055
  • 4
  • 54
  • 86
  • Note an *abstract class* cannot be instantiated (at laest in Rails 6.0); `ModelBase.new` would raise `NotImplementedError` – Masa Sakano Nov 10 '20 at 11:36
  • 1
    @MasaSakano It's also not needed in Rails 6. `ActiveModel` is already what an `ActiveRecord` with `abstract_class` is. – Itay Grudev Nov 10 '20 at 22:03
  • `ActiveModel` and `ActiveRecord` are different. For example, having an object include ActiveModel would allow you to use that model in forms and views. But it won't allow you to use `store_accessor`. Methods that are defined in ActiveRecord. In my case, I would like to test some concerns, but not by testing the ActiveRecord object where I included the module, but on a "virtual" or new object defined in the test file. This is not possible to do with just including ActiveModel since the concern is using `scope` and `store_accessor`. – chopi321 Nov 05 '21 at 15:48
1

If you want to have a select list (which does not evolve) you can define a method in your ApplicationHelper that returns a list, for example:

 def my_color_list
   [
     "red",
     "green",
     "blue"
   ]
 end
Stéphane Bruckert
  • 21,706
  • 14
  • 92
  • 130
hkairi
  • 385
  • 2
  • 9
  • Yeah but `collection_select` only accepts models that respond to method names. http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-collection_select – Chloe Jun 10 '17 at 19:47