0

I'm fairly confused and would appreciate some help.

I'm going through the Michael Hartl tutorial and the most complicated aspect (for me) is simply understanding what I perceive to be inconsistencies in syntax (I know I'm wrong in this regard and it's just my perception).

I'm currently on chapter 8, however a simple example from earlier on:

def show
  @user = User.find(params[:id])
end

And another:

 def create
  @user = User.new(user_params)
  if @user.save
    log_in @user
    flash[:success] = "Welcome to the Sample App!"
    redirect_to @user
  else
    render 'new'
  end
end

As far as I understand instance variables, they are supposed to be attributes of the object or instance of the class, eg, :name, :email, :password_digest, etc.

In these examples, we haven't written an initialize method for the class as we simply generated a migration with 4/5 columns (which correspond with the attributes specified); the columns in this migration are, as I understand, interpreted by Rails as attributes or instance variables of the instance of the class (the object?)

What then is @user or rather why is an instance variable used in this context? It isn't an attribute (eg, :name) of an instance of the class, but rather appears to be a reference, placeholder or representation of an instance of the class?

n.b. I understand (well, as far as beginners understand) what the code above does, ie, queries the User model - which is also called User - to retrieve a record, however I don't understand why this is being assigned to an instance variable or in what contexts to use instance variables, ie, I thought they were for specifying attributes for an instance of the class, not for operating as a placeholder or referencing an instance of the class (including its attributes).

EDIT: I think my confusion emanates from instance variables being used for both specifying attributes and for, as per Mark's definition below, 'operating as a container for all the attributes of a class.'

The above examples appear to use instance variables as a 'container for attributes', whereas other examples I've read use instance variables to store attribute values.

An example from earlier in the book:

def initialize(attributes = {})
@name = attributes[:name]
@email = attributes[:email]
end

I guess it's both?

clickwork
  • 1
  • 2
  • Please read "[ask]" including the linked pages; "Pretend you're talking to a busy colleague" applies to the body, not just the title. I'd recommend stripping your question to be very concise and to the point. There is a lot of text that isn't important to the question. Clarity is very important and asking people to read non-essential information discourages potential answerers or those in the future who are searching for similar information. – the Tin Man Mar 22 '17 at 22:22
  • Probably related: http://stackoverflow.com/q/18855178/477037. From the [book](http://railsoopbook.com/), Sergio Tulentsev is [mentioning](http://stackoverflow.com/questions/18855178/how-are-rails-instance-variables-passed-to-views#comment27821398_18855178) in the comments: _"the role that instance variables play in a Rails controller has absolutely nothing to do with being an instance variable"_ – Stefan Mar 22 '17 at 22:42

1 Answers1

0

From rubyist.net:

An instance variable has a name beginning with @, and its scope is confined to whatever object self refers to. Two different objects, even if they belong to the same class, are allowed to have different values for their instance variables.

So to answer your question: Yes, an instance variable is referring to an instance of a class and is not the same thing as an attribute of a class. More accurately, an instance variable is simply a container for all the attributes of a class (in this case the User class). Whenever you use the @user syntax, you're saying that you want to create your own instance of a user, with separate values for the user's attributes than say, another instance variable.

I could create two instance variables like this:

@user1 = User.new
@user2 = User.new

Now, I can assign attributes to the users separately like this:

@user1.email = "test@exmample.com"
@user2.email = "anotheremail@example.com"

Each instance of this user is unique, and that is the core concept behind instance variables.

For rails, however, any instance variables you declare in your controller will be accessible in the corresponding view, which is why you can access the @user variable in, say, your new.html.erb file.

EDIT

Here's the code you updated your post with:

def initialize(attributes = {})
  @name = attributes[:name]
  @email = attributes[:email]
end

The initialize method is actually the method that gets called when you create a new object. For example if I created a new user object, I'd do it like this:

@user = User.new

By default, the initialize method for the User class will get called when I do this. Also, you'll notice that the initialize method takes one parameter called attributes. The parameter is defined like this:

def initialize(attributes = {})

This means that if you pass in any arguments to the new method, those arguments will be passed into the attributes parameter. the = {} simply means that if you don't pass in any arguments to the new method method, the attributes parameter will default to a blank hash.

For example, I could initialize a user object like this:

@user = User.new(name: "mark", email: "test@example.com")

the name and email parameters would be passed into the initialized method via the attributes hash. then, your code suddenly makes more sense. This line:

@name = attributes[:name]

simply assigns the name you passed into the new method to be the value of @user.name. So in this sense, the above line is confusing because it appears to be assigning an attribute to an instance variable, but it's really just assigning the value of the name attribute on the @user instance variable.

Therefore, once the initialize method returns, the @user variable would have access to the attributes you assigned in the initialize method.

More reading:

Community
  • 1
  • 1
Mark
  • 9,718
  • 6
  • 29
  • 47
  • Thanks for this - it helps. I think my confusion emanates from instance variables being used for both specifying attributes and for, as per your definition, 'operating as a container for all the attributes of a class.' The above examples appear to use instance variables as a container for attributes, whereas other examples I've read use instance variables to store attribute values. An example from earlier in the book: def initialize(attributes = {}) [at]name = attributes[:name] [at]email = attributes[:email] end I guess it's both? – clickwork Mar 22 '17 at 21:33
  • Yes, instance variable do store attribute values, and that's why I said they are a container for the attributes of their class. If `email` is an attribute of the `User` model (class), and if `@user` is an instance variable of `User`, then `@user.email = "myemail@example.com` stores an email in the `email` attribute of the instance variable. In that sense, instance variables are containers for the attributes of the parent class. – Mark Mar 22 '17 at 21:37
  • Thanks, Mark. Appreciate the time you put into the answer. I understand the initialize method and your answer helps clarify what I suspected to be the case about the user instance variable. Part of my confusion was just the author conflating instance variables with 'attributes' of an instance of the class and then using an instance variable to refer to the instance of the class (the object) as well as attributes of the instance of the class without much in the way of explanation. As a newb, it can be difficult to determine what context to use them in. – clickwork Mar 22 '17 at 22:23
  • @clickwork yeah I totally understand. I didn't get what you meant at first, but now I do and can definitely see why it's confusing. Good luck as you keep learning rails! :) – Mark Mar 22 '17 at 22:24
  • Please don't use "edit" or "update" tags in the text. Instead incorporate the change into the text as if it was there from the beginning. We can see what changed and when if it's necessary as SO maintains revision history of questions and answers. – the Tin Man Mar 22 '17 at 22:26
  • @theTinMan I know there's a revision history, but I usually feel that it's easier for the OP to visually see where the edit starts when the edit tag is there. Thanks for your input though :) – Mark Mar 22 '17 at 22:30
  • I'd recommend reading: "[Should 'Edit:' in edits be discouraged?](https://meta.stackoverflow.com/questions/255644/)" along with the related posts. – the Tin Man Mar 22 '17 at 22:41