Attr_Accessor, Not Able to Access Property

attr_accessor, not able to access property

Looks like group_id is already a property on your Foo object (shown by the fact that it returns 106 when attr_accessor is omitted). By adding attr_accessor you are overriding what's already there and creating a method reader and writer called group_id. The return of the newly defined group_id is nil since you don't define anything.

Conceptually, you're ending up with something like this:

class Foo < ActiveRecord::Base
def group_id # overriding previous definition of 'group_id'
nil
end
end


Edit:

If your goal is expose properties then yes, use attr_accessible

methods created by attr_accessor are not available to sub classes

What you're looking for is cattr_accessor which fixes this specific problem:

http://apidock.com/rails/Class/cattr_accessor

Here's your example, fixed:

class Human
def self.age
@age = 50
end
def self.age=(input)
@age = input
end

cattr_accessor :name

self.name = 'human'
end
class Boy < Human
end

puts Human.age
puts Boy.age
puts Human.name
puts Boy.superclass.name
puts Boy.name # => 'human'

Property from attr_accessor does not show when I render json

render json: user, methods: [:score]

attr_accessor is alternative for getter and setter method so it is a method and as I have mentioned we can call it as above

Why can't I use attr_accessor inside initialize?

You can't call attr_accessor on the instance, because attr_accessor is not defined as an instance method of MyClass. It's only available on modules and classes. I suspect you want to call attr_accessor on the instance's metaclass, like this:

class MyClass
def initialize(varname)
class <<self
self
end.class_eval do
attr_accessor varname
end
end
end

o1 = MyClass.new(:foo)
o2 = MyClass.new(:bar)
o1.foo = "foo" # works
o2.bar = "bar" # works
o2.foo = "baz" # does not work

What is attr_accessor in Ruby?

Let's say you have a class Person.

class Person
end

person = Person.new
person.name # => no method error

Obviously we never defined method name. Let's do that.

class Person
def name
@name # simply returning an instance variable @name
end
end

person = Person.new
person.name # => nil
person.name = "Dennis" # => no method error

Aha, we can read the name, but that doesn't mean we can assign the name. Those are two different methods. The former is called reader and latter is called writer. We didn't create the writer yet so let's do that.

class Person
def name
@name
end

def name=(str)
@name = str
end
end

person = Person.new
person.name = 'Dennis'
person.name # => "Dennis"

Awesome. Now we can write and read instance variable @name using reader and writer methods. Except, this is done so frequently, why waste time writing these methods every time? We can do it easier.

class Person
attr_reader :name
attr_writer :name
end

Even this can get repetitive. When you want both reader and writer just use accessor!

class Person
attr_accessor :name
end

person = Person.new
person.name = "Dennis"
person.name # => "Dennis"

Works the same way! And guess what: the instance variable @name in our person object will be set just like when we did it manually, so you can use it in other methods.

class Person
attr_accessor :name

def greeting
"Hello #{@name}"
end
end

person = Person.new
person.name = "Dennis"
person.greeting # => "Hello Dennis"

That's it. In order to understand how attr_reader, attr_writer, and attr_accessor methods actually generate methods for you, read other answers, books, ruby docs.

Using attr_accessor and attr_accessible on the same field

Thanks everyone for quick answers!
Your answers combined gave me the pieces I needed to understand this puzzle, I think.

(In a related problem, I was getting a lot of nil errors like "Object doesn’t support #inspect", and "undefined method ‘keys’ for nil:NilClass". I managed to solve it now, by removing the att_accessor field altogether.)

By experimenting with this particular case, this is what I've found out:

Actually, the :name field won't be persisted to the database.

user = User.new(:name=>"somename")

Will only set the attribute on the object, but not persist the :name column to the database. Like the following 'rails console' output shows:

> user
=> <User id: nil, created_at: nil, updated_at: nil>
> user.save
=> true
> user
=> <User id:1, created_at: 2011-01-19 12:37:21, updated_at: 2011-01-19 12:37:21>

I assume this is because *the setter made by attr_accessor will override ActiveRecord's setter* (which takes care of the database persistence). You can still retrieve the value from the :name field from the object though, like this:

> user.name
=> "somename"

So, in conclusion, I've learnt that using attr_accessor on fields might lead to them not being persisted to the database. And while I thought attr_accessible describes fields in the database that should be accessible from the outside, it doesn't seem to make a difference in this case.

Why attr_accessor won't work in setting methods

It's actually totally OK to use instance variables within instance methods. In fact, that's what they're for! Setters and getters allow things outside the instance to access variables inside the instance. They (basically) define instance methods for the class like this:

class Foo
# getter -- Same as attr_reader :root
def root
@root
end

# setter -- Same as attr_writer :root
def root=(root)
@root = root
end

# attr_accessor defines a setter *and* a getter.
end

So, you could simplify your code by defining #insert so that it only takes one argument (value) and replace every place where you reference node with a reference to @root.

The way that I think you're looking for (but is not the "right" way, and I wouldn't recommend) is to call the root and root= methods defined by the accessor.

If you took this route, you'd also have to define #insert to only take value as an argument and replace every place that you reference node with root. This will work, but it's not the right way to solve the problem. If you solve it this way, please ask a question on CodeReview.se so I can clarify how you can make the code better.

Why it's not working

In the #insert method, you're manipulating the node parameter that was passed to the method, not root. Ruby is pass by value not pass by reference (sorta), so when you pass mybst.root to #insert, you're effectively passing nil because mybst.root == nil. Then the mybst.insert call returns a new Node, but you don't do anything with that return value. If you wanted to set root to that return value, you could do:

mybst = BST.new
p mybst.root
mybst.root = mybst.insert(1, mybst.root)
mybst.root = mybst.insert(2, mybst.root)
mybst.root = mybst.insert(10, mybst.root)
mybst.root = mybst.insert(12, mybst.root)

p mybst

Explanation of what that textbook is trying to say

I think that the confusing part here is where the textbook says:

Hide the variables, even from the class that defines them

This is correct, but I think you're misinterpreting it. This section is saying that you should hide instance variables from anything outside of that instance. Within that instance, it's totally OK to use them, and that's actually the reason why instance variables exist -- to store state within the instance. It's just considered better to define methods for behaviors rather than directly exposing the instance variables. Of course, this is just one rule to keep in mind -- I'm sure you'll come across a situation where this advice does not apply, but generally you want to keep instance variables internal.

Why do we need attr_accessor?

Because it makes the code easier to maintain.

This way its clear from reading the class code what you expect to have happen, and that you expect other classes to access these variables.

Without this outside code could simply access your internal variables, and then if you refactor your code and remove or rename such a variable the outside code breaks.

Thus the accessor methods make it clear you intend for other classes to access these methods

FYI: Ruby is very powerful, and if you want you can go ahead and make it work the way you want. I don't recommend this but am pointing it out so you will understand that its a explicit choice being made for the good of keeping your code readable. But if you want to see how you could do this read on, and try running the code...

<script type="text/ruby">
def puts(s) # ignore this method, just dumps to the display Element['#output'].html = Element['#output'].html + s.to_s + "<br/>"end
class OpenKimono def method_missing(name, *args) if name =~ /=$/ instance_variable_set("@#{name[0..-2]}".to_sym, args[0]) else instance_variable_get("@#{name}") end endend
class MyClass < OpenKimonoend
foo = MyClass.new
foo.bar = 12
puts "foo.bar just set to 12, it now = #{foo.bar}"
foo.baz = 13
puts "foo.baz just set to 13, it now = #{foo.baz}"
puts "foo.manchu has never been set... what does it equal? #{foo.manchu}"
</script>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><script src="https://rawgit.com/reactive-ruby/inline-reactive-ruby/master/inline-reactive-ruby.js"></script><div id="output" style="font-family: courier"></div>

Cannot retrieve attr_accessor in Rails 4

I wouldn't override the create_merchant method if I were you, try something like this:

after_create -> { create_merchant!(:name => self.merchant_name) }

and make sure your merchant_name is permitted in the users controller, something like this:

def create
@user = User.new(user_params)
if @user.save
redirect_to @user
else
render :new
end
end

private

def user_params
params.require(:user).permit(:merchant_name, :email, :password, :password_confirmation)
end


Related Topics



Leave a reply



Submit