How to add user defined attribute to a model - ruby-on-rails

I'm adding ":foo" attribute to my user model as:
attr_accessor :foo
attr_accessible :foo
But when I set this attribute from a session controller or any other controller as:
User.foo = "my attributre"
and I get this attribute as:
User.foo
so these are not recognize and gives me an error, which is:
undefined method `foo=' for #<Class:0xb75366fc>
So please help here. I AM USING RAILS 2.3.5

attr_accessor does not create a class method, it creates instance methods. So given your code, it should work to use:
#user = User.new
#user.foo = "bar"
Edit:
However, if you do want to create custom methods, then you could do something like this:
class User < ActiveRecord::Base
def self.add_accessor(attr)
define_method(attr) do
instance_variable_get("##{attr}")
end
define_method("#{attr}=") do |val|
instance_variable_set("##{attr}",val)
end
end
And then you call it from your Controller:
User.add_accessor "foo"
#user = User.new
#user.foo = "bar"

Try this if you want to have an attribute accesor at the class level
In the User model , Use this code
class << self
attr_accessor :foo
end
Further reference http://apidock.com/rails/Class/cattr_accessor

Related

How to access class method from instance method in ruby on rails non activerecord model

I have a non activerecord rails model:
class Document
attr_accessor :a, :b
include ActiveModel::Model
def find(id)
initialize_parameters(id)
end
def save
...
end
def update
...
end
private
def initialize_parameters(id)
#a = 1
#b = 2
end
end
In order to find the Document, I can use:
Document.new.find(3)
So, to get it directly I changed the find method to
def self.find(id)
initialize_parameters(id)
end
And I get the following error when I run
Document.find(3)
undefined method `initialize_parameters' for Document:Class
How can I make this work?
You can't access an instance method from a class method that way, to do it you should instantiate the class you're working in (self) and access that method, like:
def self.find(id)
self.new.initialize_parameters(id)
end
But as you're defining initialize_parameters as a private method, then the way to access to it is by using send, to reach that method and pass the id argument:
def self.find(id)
self.new.send(:initialize_parameters, id)
end
private
def initialize_parameters(id)
#a = 1
#b = 2
end
Or just by updating initialize_parameters as a class method, and removing the private keyword, that wouldn't be needed anymore.
This:
class Document
attr_accessor :a, :b
def self.find(id)
initialize_parameters(id)
end
end
Is not trying to "access class method from instance method" as your title states. It is trying to access a (non-existent) class method from a class method.
Everything Sebastian said is spot on.
However, I guess I would ask: 'What are you really trying to do?' Why do you have initialize_parameters when ruby already gives you initialize that you can override to your heart's content? IMO, it should look something more like:
class Document
attr_accessor :a, :b, :id
class << self
def find(id)
new(id).find
end
end
def initialize(id)
#a = 1
#b = 2
#id = id
end
def find
# if you want you can:
call_a_private_method
end
private
def call_a_private_method
puts id
end
end

Accessing instance variable in rails and ruby

I am new to ruby and rails and sometimes I still get confused between these two. I have tried to call an instance variable by adding a name of the instance variable after an object(john.name), and I hope that the result would be John. Unfortunately NoMethodError appears. So I searched for an answer and found out that you can use instance_variable_get method to do this. However, I believe that it is possible to do this in RAILS when you want to access the instance variable of an object in VIEWS.
class Person
def initialize(name)
#name = name
end
end
john = Person.new("John")
puts john.instance_variable_get(:#name)
=> John
puts john.name
=> NoMethodError
Use attr_reader to read the value of an instance variable
class Person
attr_reader :name
def initialize(name)
#name = name
end
end
john = Person.new("John")
john.name #=> "John"
attr_reader adds a getter method to the class, in this case
def name
#name
end
Hope that helps!
You need to define the method to access your instance variable.
class Person
def initialize(name)
#name = name
end
def name
#name
end
end
Or you can simply add attr_accessor which will set getter and setter methods
class Person
attr_accessor :name
def initialize(name)
#name = name
end
end

Is there a way to override the << operator in Ruby?

I'm trying to do something like:
account.users << User.new
But I need users to be a method on an account. So I've tried things like:
def users<<(obj)
But I've had no luck with that. Is this even possible to do in Ruby? I would assume so because the ActiveRecord relationships seem to work this way in Rails.
Check this answer: Rails: Overriding ActiveRecord association method
[this code is completely from the other answer, here for future searchers]
has_many :tags, :through => :taggings, :order => :name do
def << (value)
"overriden" #your code here
end
end
It seems like you might not be describing your actual problem, but to answer your question -- yes you can override the << operator:
class Foo
def <<(x)
puts "hi! #{x}"
end
end
f = Foo.new
=> #<Foo:0x00000009b389f0>
> f << "there"
hi! there
I assume you have a model like this:
class Account < ActiveRecord::Base
has_and_belongs_to_many :users
end
To override Account#users<<, you need to define it in a block that you pass to has_and_belongs_to_many:
class Account < ActiveRecord::Base
has_and_belongs_to_many :users do
def <<(user)
# ...
end
end
end
You can access the appropriate Account object by referring to proxy_association.owner:
def <<(user)
account = proxy_association.owner
end
To call the original Account#users<<, call Account#users.concat:
def <<(user)
account = proxy_association.owner
# user = do_something(user)
account.users.concat(user)
end
For more details, see this page: Association extensions - ActiveRecord
In this case it's the << of you class of you User. So can be an Array or a AssociationProxy.
The must simplest is create a new method to do what you want.
You can override the method by instance instead.
account.users.instance_eval do
def <<(x)
put 'add'
end
end
account.users << User.new
# add
But you need do that all the time before you add by <<
users would return an object that has overridden << operator like Array, IO, String, or any type you create. You override like this:
class SomeType
def <<(obj)
puts "Appending #{obj}"
end
end
If you are trying to perform an action upon adding an User to the users collection, you can use association callbacks instead of over-riding <<(as there are many ways to add an object to an association).
class Account
has_many :users, :after_add => :on_user_add
def on_user_add(user)
p "Added user : #{user.name} to the account: #{name}"
end
end

Using the save method together with update_attributes. Is this common?

A user can sign up as an artist. All the user needs to do now, is provide his email.
In Artist controller, def create. Is it normal to have something like:
def create
#artist = current_user
respond_to do |format|
if #artist.update_attributes(params[:user]) # params[:user] contains email
#artist.is_artist = true
#artist.save
....
In my User model, I have:
attr_accessible :email
Which means, I can't simply do #artist.update_attributes(:is_artist => true). I would have to use the save method instead. Is this type of approach common? Or is there a better way?
You can define before_create method in your model:
class User < ActiveRecord::Base
...
before_create :fill_fields
def fill_fields
is_artist = true
end
end
I would do the following:
1st: I wound not set up an ArtistController if you do not have an Artist Model. rather I would add a non-restful method in your UserController, and push the implemention logic into the model ...
# config/routes.rb
resources :users do
member {post 'signup_as_artist'}
end
# UserController
def signup_as_artist
#user = User.find(params[:id])
#user.signup_as_artist
end
# User
def signup_as_artist
self.update_attribute :is_artist, true
end
Good luck

Creating Rails ActiveRecord model from params hash

Most Rails tutorials show how to populate a model class via the params hash like so:
class UsersController < ApplicationController
def create
#user = User.create(params[:user])
# more logic for saving user / redirecting / etc.
end
end
This works great if all the attributes in your model are supposed to be strings. However, what happens if some of the attributes are supposed to be ints or dates or some other type?
For instance, let's say the User class looks like this
class User < ActiveRecord::Base
attr_accessible :email, :employment_start_date, :gross_monthly_income
end
The :email attribute should be a string, the :employment_start_date attribute should be a date, and the :gross_monthly_income should be a decimal. In order for these attributes to be of the correct type, do I need to change my controller action to look something like this instead?
class UsersController < ApplicationController
def create
#user = User.new
#user.email = params[:user][:email]
#user.employment_start_date = params[:user][:employment_start_date].convert_to_date
#user.gross_monthly_income = params[:user][:gross_monthly_income].convert_to_decimal
# more logic for saving user / redirecting / etc.
end
end
According to the ActiveRecord documentation, the attributes should automatically be typecasted based on the column types in the database.
I would actually add a before_save callback in your users model to make sure that the values you want are in the correct format i.e.:
class User < ActiveRecord::Base
before_save :convert_values
#...
def convert_values
gross_monthly_income = convert_to_decimal(gross_monthly_income)
#and more conversions
end
end
So you can just call User.new(params[:user]) in your controller, which follows the motto "Keep your controllers skinny"

Resources