Closest comparison is JavaScript class functions. In Ruby, it is very infrequent for a method to be defined outside of a class. Taking this example from the MDN docs on Classes:
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
// Getter
get area() {
return this.calcArea();
}
// Method
calcArea() {
return this.height * this.width;
}
}
const square = new Rectangle(10, 10);
console.log(square.area); // 100
The equivalent Ruby class would be:
class Rectangle
attr_reader :height, :width
def initialize(height, width)
@height = height
@width = width
end
def calc_area
@height * @width
end
def another_method(arg1, arg2)
"do some stuff" + calc_area.to_s
end
end
square = Rectangle.new(10, 10)
puts square.calc_area
Things you can see here:
- Methods implicitly return the value of the last expression in the method, but that can be made explicit (or forced to return earlier than that and break off executing the method) with
return
just like in JS. - No end-of-line syntax like JS (
;
), line breaks are assumed to close an expression unless the next line starts with a.
to chain methods. initialize
works just likeconstructor
.- Ruby prefers
do ... end
instead of curly braces ({ ... }
) but in some cases (such as iteration/enumerable blocks) accepts either. When defining classes and methods, the openingdo
is implied. - The equivalent of "instance properties" are "instance variables" in Ruby and they are preceded by an
@
; but unlike instance properties, they are not accessible from outside the Class scope unless you explicitly make a "getter" method for them withattr_reader
followed by a symbol reference for it (the name of the property preceded by a colon), and then only read-only. For read/write (getter/setter),attr_accessor
is used. - Unlike JS, if a method does not take an argument you don't need to include parentheses afterward, both when defining it and when calling it. This can make it challenging, at a glance, to tell the difference in Ruby between a local variable and a method; a quick "find in file" or "find in project" is the best way to clarify, but generally if you don't see a local variable by that name defined in that method or passed in as an argument then it is a method and you'll either find it elsewhere in that class or in another class (or module) it inherits from.
- As probably became clear in that last example, Ruby is much more encapsulated by default than JS, preferring to keep data contained to its class or method whenever possible.
- Local variables are what you'll most frequently see. They are block-scoped and exist only for duration of the execution of a particular block, and are declared without any keyword:
example_variable = "An example value!"
They are mutable, so they can be re-assigned as many times as you'd like. - There is no (to my knowledge) equivalent of "hoisting" in Ruby; assignment occurs in the order lines of code are executed.
- Instance variables and instance methods can be accessed anywhere within the class. There is an odd extension of this logic when it comes to Controllers and Views in Rails, which we'll see later.
- Anatomy of a normal ("hand-rolled") route and how to find associated controller and "action"
- How dynamic segments work and how they're passed to controller through
params
- A quick overview of how "resources" automate route creation
- Namespaces and how they affect where the controller file is looked for
- View available routes with
rake routes
-
Controllers are task-specific Ruby classes. From the Rails Action Controller docs:
A controller is a Ruby class which inherits from ApplicationController and has methods just like any other class. When your application receives a request, the routing will determine which controller and action to run, then Rails creates an instance of that controller and runs the method with the same name as the action.
-
The ApplicationController class always lives at
app/controllers/application_controller.rb
, and because its methods are inherited by all controllers it often has methods which relate to user authentication, cookies, sessions, and other things that every part of the app needs access to. -
By default, a controller action will render the view file corresponding to that controller and action. So this controller:
class ClientsController < ApplicationController def new end end
would render
app/views/clients/new.html.erb
. The important thing to note is that it renders that View file within thenew
action method after all other lines have executed, so that View has access to any instance variables (but not local variables) declared in that action. -
However, a controller can explicitly render a View other than what the default would be, using the
render
function followed by a string with the folder and name of the appropriate view.- The view might be a "partial," i.e. a partial template, which is meant to be re-used across multiple views. If so, the filename of that partial will have an underscore prepended, like
_example_partial.html.erb
.
- The view might be a "partial," i.e. a partial template, which is meant to be re-used across multiple views. If so, the filename of that partial will have an underscore prepended, like
-
In the MVC flow, the first thing a Controller typically does is retrieve or change data by way of a Model.
- In SQL/relational databases (RDBs), information is stored on tables which are related to each other through primary keys (columns on each table with a unique identifier for each row) and foreign keys (a reference to another row's primary key, typically a row on a different table).
- SQL (structured query language) is the language used to create, read, update, and delete (CRUD) data on the tables in a relational database. It is powerful but somewhat complex, following a different kind of logic than what we typically do while coding.
- Rails comes shipped with ActiveRecord, an object relational mapper (ORM) library which allows you to interact with your RDB data as if each table was a class and each row on that table is an instance of that class. It also allows you to interact with the DB using Ruby methods instead of SQL by turning ActiveRecord functions into SQL queries behind the scenes.
- For each table in the database, there will be a Model class. By default every instance of that class will have a reader method for each column on the table, but the Model class allows you to define additional instance methods; this is typically where data logic lives in a Rails app.
- The Model class is also typically home to any (ActiveRecord) queries against that table as a whole which need to return instances of that class. For example, if I wanted to retrieve all the Users with a certain number of purchases that included items sold by a given merchant, even though that query involves multiple tables it would be a class method (not inherited by instances) on the User model because I want to retrieve User objects.
- As described earlier, Views are rendered by Controller actions.