0

This might be a noob question but here it goes:
I'm trying to parse embbeded ruby code and I need some help in understanding the synthax for methodcalls and variable accesing in embedded ruby scripts.
For example in this call @user.followed_users.count (as I understand it) @user is an instance of a the user model followed_users is a (automatically generated) method and count is also a method right?
But what are these calls micropost.content micropost.created_at micropost.user? They are from this erb file:

<li>
  <span class="content"><%= micropost.content %></span>
  <span class="timestamp">
    Posted <%= time_ago_in_words(micropost.created_at) %> ago.
  </span>
  <% if current_user?(micropost.user) %>
    <%= link_to "delete", micropost, method: :delete,
                                     data:{ confirm: "You sure?" },
                                     title: micropost.content %>
  <% end %>
</li> 

(these are code examples from this michael hartl rails tutorial)

What kinds of syntaxes for method calls and variable accessing from erb files are there in Rails? Is it possible to access variables from ruby files that are not instance or class variables?

Thanks in advance for reading and helping :)

max
  • 96,212
  • 14
  • 104
  • 165
pokeahontas
  • 27
  • 2
  • 8

2 Answers2

1

The syntax is the same.

There are no major syntactical differences between ERB and Ruby except that ERB is an embedded language where only the code in "erb" tags are executed <% %>.

Whats the difference between a local variable and a method?

A method is a method object that is defined on an object.

def foo
  "hello world"
end

# we can call it by
self.foo

# we can access the method object by
self.method(:foo)

This defines the method foo on main.

bar = "value"

Defines the locally scoped variable bar. Not that you can't do self.bar since it just points to a memory register, not a method! You don't call variables - you reference them*. Thus the term "variable call" is just wrong.

As @SergioTulentsev points out you can check if a micropost is a local variable or method by using defined?. Note the caveat when using rails locals below.

See:

Using ERB outside of rails

In Ruby the top level object is called main which is the "global" object. When you assign a instance variable <% @foo = "bar" %> you are assigning it to main which is the implicit self.

<%# raw_template.erb %>
<%= self.inspect %>

If we run erb raw_template.erb it will output main.

Assigning a regular lexical variable (a local) <% foo = "bar" %> works just like in any other ruby code.

As you can see is no difference in how variables work in an ERB template and any other Ruby code.

What does rails do differently?

A core piece of Rails is what is called the view context. This is an instance of ActionView::Base which is the implicit self - the "global" object.

You don't have to take my word for it. Try including this in a view in Rails:

<pre>
  <%= self.inspect %>
</pre>

Rails takes all the instance variables of the controller and assigns them to the view context. Which why the @something instance variable you assign in your controller is also available to your views.

Rails locals are not really local variables

The view context also contains a hash called local_assigns. These are the "local variables" you can pass when rendering a template:

render template: 'test', locals: { foo: 'bar' }

When you call <%= foo %> in the test.html.erb template the call goes to method_missing which checks if local_assigns has a :foo key.

Thats why using defined? on local_assigns variables does not work as expected.

But the syntax is the same.

Rails uses a bit of metaprogramming magic to pass variables around - but it does not alter the syntax of the language.

Is it possible to access variables from ruby files that are not instance or class variables?

Yes, global variables - in Ruby you create a global variable by using the sigil $.

$foo = "bar"

But this is rarely used because globals are evil. And there are better ways to it in Ruby.

Community
  • 1
  • 1
max
  • 96,212
  • 14
  • 104
  • 165
  • * yes you can call a local variable if it happens to be a callable type like a Proc. But you're actually just referencing an object and calling its `.call` method. – max Apr 25 '17 at 14:16
0

micropost in <%= micropost.content %> can be a local variable OR a method. There's no way to tell which is it, just by looking at the line. All that matters is micropost evaluates to something you can call .content on.

If you want to know which is it (for education), you can output its type like this:

<%= defined?(micropost) %>

It'll return either "local-variable" or "method" (or nil, if it's not defined).

Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367