ViewModel - controller in Rails instead of ActiveRecord?

I am trying to use ActiveModel instead of ActiveRecord for my models because I do not want my models to have anything to do with the database.

Below is my model:

class User include ActiveModel::Validations validates :name, :presence => true validates :email, :presence => true validates :password, :presence => true, :confirmation => true attr_accessor :name, :email, :password, :salt def initialize(attributes = {}) @name = attributes[:name] @email = attributes[:email] @password = attributes[:password] @password_confirmation = attributes[:password_confirmation] end end 

And here is my controller:

 class UsersController < ApplicationController def new @user = User.new @title = "Sign up" end end 

And my opinion:

 <h1>Sign up</h1> <%= form_for(@user) do |f| %> <div class="field"> <%= f.label :name %><br /> <%= f.text_field :name %> </div> <div class="field"> <%= f.label :email %><br /> <%= f.text_field :email %> </div> <div class="field"> <%= f.label :password %><br /> <%= f.password_field :password %> </div> <div class="field"> <%= f.label :password_confirmation, "Confirmation" %><br /> <%= f.password_field :password_confirmation %> </div> <div class="actions"> <%= f.submit "Sign up" %> </div> <% end %> 

But when I load this view in the browser, I get an exception:

 undefined method 'to_key' for User:0x104ca1b60 

Can anyone help me with this?

Thank you very much in advance!

+15
ruby ruby-on-rails ruby-on-rails-3 activemodel
Jul 17
source share
2 answers

I participated in the source of Rails 3.1, to understand this, I realized that it would be easier than searching elsewhere. Earlier versions of Rails should be similar. Go to the end if tl; dr.




When you call form_for(@user) , you end this:

 def form_for(record, options = {}, &proc) #... case record when String, Symbol object_name = record object = nil else object = record.is_a?(Array) ? record.last : record object_name = options[:as] || ActiveModel::Naming.param_key(object) apply_form_for_options!(record, options) end 

And since @user is neither a string nor an object, you go through the else branch also in apply_form_for_options! . Inside apply_form_for_options! we see the following:

 as = options[:as] #... options[:html].reverse_merge!( :class => as ? "#{as}_#{action}" : dom_class(object, action), :id => as ? "#{as}_#{action}" : dom_id(object, action), :method => method ) 

Pay attention to this piece of code, it contains both the source of your problem and the solution. The dom_id method calls record_key_for_dom_id , which looks like this:

 def record_key_for_dom_id(record) record = record.to_model if record.respond_to?(:to_model) key = record.to_key key ? sanitize_dom_id(key.join('_')) : key end 

And here is your call to_key . The to_key method to_key defined by ActiveRecord::AttributeMethods::PrimaryKey , and since you are not using ActiveRecord, you do not have a to_key method. If you have something in your model that behaves like a primary key, then you can define your own to_key and leave it to that.

But if we go back to apply_form_for_options! , we will see another solution:

 as = options[:as] 

So you can provide :as a form_for option to create a DOM identifier for your form manually:

 <%= form_for(@user, :as => 'user_form') do |f| %> 

You need to make sure that :as was unique on the page.




Summary :

  • If your model has an attribute that behaves like a primary key, then define your own to_key method, which returns it.
  • Or put the appropriate option :as on form_for .
+31
Jul 17 '11 at 5:45 a.m.
source share

It looks like you should investigate the (not very well documented) ActiveModel :: Conversions class

https://github.com/rails/rails/blob/3-1-stable/activemodel/lib/active_model/conversion.rb

  include ActiveModel::Conversion def persisted? false end 

would do the trick the same applies to Rails 4.2

+1
Jun 14 '16 at 21:49
source share



All Articles