In the RoR view You often need to display lists of some models. If You use instance variables for this, like #people and countries, RubyMine IDE will warn You that You should use at most two instance variables in the view.
So let's say You will wrap those in a hash, like:
view_params = { people: #people, countries: #countries }
I know naming is very important in RoR. Is there any naming convention for such hash, which I called view_params (in Django they call it context I guess), or good practice how to deal with this problem?
It's a stupid rule. Turn off the rule in your IDE.
Stick to the better rule - "Methods can be no longer than five lines of code." If you find your controller methods becoming longer than five lines because you're building too many instance variable - then package them up. But if you can create all the instance variables you want in about 5 lines of code, then that's fine.
If you look at the example in Sandi Metz Rules For Developers, all they've done is package the instance variables into another object. Is there really a good reason why having two instance variables associated with a controller instance is worse than making them belong to a new object instance?
For me:
def index
#foo = Foo.get_some
#bar = Bar.get_some
end
Is cleaner and simpler than:
class FooBar
attr_reader :foo, :bar
def initialize(foo, bar)
#foo = foo
#bar = bar
end
end
class FooBarController
def index
foo = Foo.get_some
bar = Bar.get_some
#foo_bar = FooBar.new(foo, bar)
end
end
Use a non-active record ruby class instead of a hash. One instance variable is probably best. See facade pattern: https://robots.thoughtbot.com/sandi-metz-rules-for-developers
Related
what is right way of writing module? is it only used to stock some peace of code to minimize the number of lines, or is it something much more important than that
I have used and seen ways of writing module, I am working on setting up correct way to define and standardised module. this example is kind of controller code that we use in rails
Way 1 :-
module B
extend ActiveSupport::Concern
def process_items
# do somthing...
#items.pluck(:names)
end
end
Class A
include B
def index
#items = Item.all
#item_names = process_items
end
end
Way 2 :-
module B
extend ActiveSupport::Concern
def process_items(items)
# do somthing...
items.pluck(:names)
end
end
Class A
include B
def index
#items = Item.all
#item_names = process_items(#items)
end
end
Way 1 :-
When I see this independently, its not much readable as I don't know how #items appeared in this method
Unit testing would be hard for method as its dependent
Way 2 :-
Looking at method I can see input is coming we are processing it and returning it back (readablity is good)
Unit testing is easy to this, we wll call method pass what it needs and expect
The way I see modules should be independent, self explanatory, it should be generic so that can be used in any class, kind of helpers. But other way could be dependent on where we use modules
We are using modules like in rails
We use conccern in models, when we call module method we can use self.<field> we don't need to pass anything because instance variable is supposed to be accesssable in every instance method
View helpers are modules I see they put logic into it hard to understand how the variable come from may be instance variable or params, what about making it method which accept somthing and return it back
Concerns on controllers, like the example I have given
I would like to have thoughts on this, what is best approach out of it? is it something which can be standarise or it is more situational or I don't know yet :)
Note: -
I was looking at this question but answer given on this question is no more valid as referenced links are not working.
Right Way to Use Module
The difference here is practically academic, as if you have attr_reader :x then both #x and x will have the same meaning.
It's understood that within a mixin module you will be referencing methods and/or variables that are part of the class or module doing the "mixing in". As such, seeing #x, or in your case, #items, should not come as a real surprise.
If you want to add it as an explicit argument you're sort of missing a lot of the benefits of using a mixin in the first place. You don't need to mix it in at all, you can just use it like B.process_items(...). In other words, your second approach is having an identity crisis. Is it a stand-alone module that includes Concern for no reason, or a weak mixin?
When it comes to testing, you must test the mixin in a module or class which implements the required features. In this case you need either an #items variable, or an items method, and that must have a value of the expected type.
This should be documented somewhere for clarity, but is effectively an implicit contract with anyone using this module.
In a common application we use instance variables so that we can access them in our views. But in a Rails api application what would the need be?
Is there any performance difference between using a local or instance variable In this context of Controllers?
I do not understand why rails uses instance variables in the create and index method in an api application generated by scaffold if the variable is not reused
def show
user = User.find(params[:id])
render json: UserSerializer.new(user)
end
def show
#user = User.find(params[:id])
render json: UserSerializer.new(#user)
end
In this exact example, there is no functional difference.
Is there any performance difference? Or is there material performance difference? I do not know the answer to the first question. The answer to the second question, I imagine, is 'no' unless you are doing this at some unimaginably large scale. Even then, it's hard to imagine.
BTW, you could just do:
def show
render json: UserSerializer.new(User.find(params[:id]))
end
In your example, there is no need for a variable, either user or #user.
There is a very clear practical difference in how lexical and instance variables work:
class Thing
def initialize
#ivar = "Hello World"
end
def foo
#ivar
end
end
> Thing.new.foo
=> "Hello World"
Since instance variables are attached to the instance they can be shared among methods of an object without passing by value as typically used by callbacks:
class API::V1::ThingsController < ::ApiController
before_action :set_thing, except: [:create, :index]
def show
respond_with #thing
end
# ...
private
def set_thing
#thing = Thing.find(params[:id])
end
end
This can be immensely useful when considering the convention over configuration focus of rails. Controller IVARs are also available in the view through the view context.
Lexical variables on the other hand only exist in the lexical scope where the are defined (the method, block, proc or lambda):
class Thing
def initialize
lex = "Hello World"
end
def foo
lex
end
end
> Thing.new.foo
NameError: undefined local variable or method `lex' for #<Thing:0x007f87068b5968>
They are preferable when you need a short lived variable with a local scope. Rails also has locals which is actually a hash where you can stuff things when rendering which should not be conflated with the Ruby concept of lexical variables. Rails uses method_missing in the view context to proxy to the locals hash.
The performance difference is most likely extremely negible as both are just variables that are bound to a scope - either the object or a method/block. The lexical variable will recycled by the GC when the scope is closed (the method finishes) though while an instance variable will persist with the object. This is rarely an issue though.
The performance difference will be negligible.
But there's two competing guidelines at work. One is "Always use the weakest construction." Don't use double "quotes" if you can use single 'quotes'. Don't use a regular expression if you can use String#index. Don't use an instance variable if you can use a local variable.
The other guideline is "Design for testing." If you use an instance variable, your test can inspect it with assigns(:user). That rule trumps the "weakest construction" rule. So use an instance variable, and write lots of automated tests!
there is no difference talking about functionality in that example. but creating an instance variable is to let that variable be accesible later, maybe on the view or in another method, in this case, talking about api's (you don't have views), if you do not plan to use #user in another method inside that controller for example, you don't need to create it, with just a local variable, it's enough.
talking about performance, I don't think there will be much differences, at least something noticeable.
And as a comment:
"An instance variable continues to exist for the life of the object that holds it. A local variable exists only within a single method, block or module body."
I am having some trouble understanding the syntax of variables and symbols in Ruby. I am reading a book called Agile Web Development with Rails 4. I am trying to learn both Ruby and Rails so that I can build websites.
The books and tutorials I have been reading sometimes have variables with the "#" symbol in front of them, and then some variables do not have the # symbol in front of them. What is the difference between them?
Also, I am getting confused with the colon. Sometimes I see variables where the colon is in the front, such as :order, and then I see variables where the colon is at the end, such as colon:. I do not understand what the colon is doing.
Please help me understand the Ruby syntax.
Variables starting with # are instance variables, "properties" in other languages. Whereas 'classic' variables are local to the scope of their method/block, instance variables are local to a specific instance of an object, for example:
class Foo
def initialize(bar)
#bar = bar
end
def bar
#bar # the variable is specific to this instance
end
def buzz
buzz = 'buzz' # this variable is not accessible outside of this method
end
end
You may also see variables starting with ##, which are class variables, and are accessible by every instance of the class and shared with every instance of the subclass. Usage of those variables is usually discouraged, primarily because subclasses share the variable, which can cause a lot of mess.
In Ruby everything is an object, classes are objects (instances of class Class), so you can also have class instance variables:
class Foo
def self.bar
#bar #we are in class Foo's scope, which is an instance of class Class
end
def self.bar=(bar)
#bar = bar
end
def bar
#bar # Foo.new.bar != Foo.bar
end
end
What you call "variables with a colon" are not variables. They are a particular type of string, called a symbol, that is immutable and optimized for quick identification by the interpreter, in fact, those are stored internally as pointers, so that :this == :this is a very quick operation.
This property makes them good candidates for hash keys because they offer quick retrieval or for "flags" to pass to a method; Think of them as a sort of loose constant that "stands for" what they say. Their immutability is also dangerous: All symbols ever created never get garbage collected; It's easy to create a memory-leak by creating thousands of symbols, so use them wisely.
UPDATE since ruby 2.2 symbols may be garbage-collected in certain cases (when no reference is kept and no comparison is needed)
Variables with an # symbol are instance variables. What this means is that they persist as long as the instance of the class they are declared in persists. So if you have a class called Message and each message has a variable called #subject, when you instantiate a new message it will keep that subject variable in memory as long as the message object itself lives. Now if it did not have the # symbol, once the function it was declared in "went out of scope" aka finished, the variable would be "lost" as the function was complete and the memory was reclaimed by the Ruby VM. There are also "class variables" that are prefaced with two # symbols. This means the variable is shared across all instances of a class.
As for the colon, if it is before a variable that means it is a "symbol", which is usually used as an identifer for hashes and other bits of data in Ruby. If it is at the end of a word that means it is the key portion of a hash identifier in Ruby 1.9+ syntax.
Instance Variables: (#foo = '123') An instance variable is defined and keeps its value throughout the current instance of the request. In the rails mvc paradigm, the most common use of instance variables are used to help communicate data from the controller to the view, and allows you ro define things in one part of the controller and use in another.
class ProjectsController < ApplicationController
before_filter :find_project
def show; end
def update
if #project.update_attributes(params[:project])
...
end
end
private
def find_project
#project = Project.find(params[:id])
end
end
In the above code, you can see that there is a before filter that gets ran before every method. In the above case, we find the current project and save it to an instance variable. And because its an instance method, its able to be access anywhere within this class as well as the views used to render the html.
Local Variables: (foo = '123') Pretty much exactly what the name implies, they are only able to be accessed within the current method (def) of where they are defined.
sometimes have variables with the "#" symbol in front of them, and then some variables do not have the # symbol in front of them.
Variables with the "#" symbol are instance variables,which are not preceded by #,can be constants or local variables or global variables. Read Ruby Programming/Syntax/Variables and Constants.
Sometimes I see variables where the colon is in the front, such as :order
They are called symbols.
and then I see variables where the colon is at the end, such as colon:. I do not understand what the colon is doing.
These probably the Hash syntax(as you give us hints,so I would guess),where keys are symbols. Example : {foo: 1} - this is a Hash.
Also read as you requested :
Normal Variables Vs Instance variable in Ruby, Whats the difference?
I was implementing a form that includes a hard-coded dropdown for a collection and I was wondering what would be the best solution, I know both ways exposed below work, still I did as follows:
class Example
# Options for Example.
self.options
[ 'Yes', 'No', 'Not sure' ]
end
end
which is called by Example.options, but I know it is possible to do as follows as well:
class Example
# Options for Example.
OPTIONS = [ 'Yes', 'No', 'Not sure' ]
end
that would be called with Example::OPTIONS.
The question is, is any of these the good way or it just doesn't matter at all?
The latter is better. If it were a method, a new array and new strings will be created every time it is called, which is a waste of resource.
TL;DR: It depends. Are the values meant to be used outside the class? Could they ever become dynamic? Could they change for subclasses?
As #sawa wrote, the downside of the method (written this way) is that a new array and strings are created each time.
A better way to write it would be:
class Example
def self.options
#options ||= ['Yes', 'No', 'Not sure']
end
end
The array is stored in the instance variable #options, to avoid creating a new array each time.
Written this way, the method is very similar to the constant.
One key difference is if Example is subclassed, it will be more natural to refine the options method than the constant OPTIONS:
class Parent < Example
def self.options
#options ||= [*super, 'Extra']
end
end
To do something similar with constants is difficult. Imagine that your list of options is used in a class method, this would look like:
class Example
OPTIONS = ['Yes', 'No', 'Not sure']
def self.foo(arg)
puts "Available options:",
self::OPTIONS # The self:: is needed here
# ...
end
end
class Parent < Example
OPTIONS = [*superclass::OPTIONS, 'Extra']
end
The tricky thing about constants, is that self::OPTIONS and OPTIONS are not the always same, while self.options and options are the same. Constants are usually used without specifying the scope (e.g. OPTIONS instead of self::OPTIONS) and inheritance will simply not work in that case.
Note that the method gives you the opportunity to make the result dynamic (i.e. return different results depending on other circumstances) without changing the API.
Final note: I'd recommend calling freeze on your array, to avoid anyone modifying it.
What I usually do is have a mix of above-mentioned techniques:
class Player
JURISDICTIONS = %i(de uk ru)
def self.jurisdictions
JURISDICTIONS
end
end
It has few advantages:
It provides a clean interface, encapsulating a constant (you call Player.jurisdictions instead of Player::JURISDICTIONS).
Additional logic can be added later just by altering method.
The method can be stubbed in tests.
IMHO, performance does not matter here.
Update:
Constant can bee hidden using private_constant method (http://ruby-doc.org/core-2.3.0/Module.html#method-i-private_constant)
To further refine Artur's suggestion I would go with a class variable in order to hide visibility of the constant.
class Player
##jurisdictions = %i(de uk ru)
def self.jurisdictions
##jurisdictions
end
end
I'd like to, for all helpers, across my entire Rails application, replace this syntax:
time_ago_in_words(#from_time)
with this:
#from_time.time_ago_in_words
Ideally this change would also make the helpers available anywhere in my application (the same way, say, 5.times is).
Does anyone know of a plugin that does this? Would it be difficult to roll my own?
If you create a new model you can make it inherit the methods from an existing class.
Example (app/models/mykindofstring.rb):
class Mykindofstring < String
def all_caps_and_reverse
self.upcase.reverse
end
end
Then from the controller:
#my_string = Mykindofstring.new('This is my string')
and finally calling it from the view:
<%= #my_string %>
displays as This is my string, while:
<%= #my_string.all_caps_and_reverse %>
displays as GNIRTS YM SI SIHT.
The class inherits from the string class, so all the methods that apply to a string also apply to a mykindofstring object. The method in it is just a new name for a combination of two existing string methods, but you can make it do whatever you want, such as a method to convert a time into a formatted string.
Basically it's just extending a current Ruby class with your own methods instead of using functions/helpers.
Major Edit
Based on Ians comment to this answer and his own answer to the above question, I played around a bit in Rails and came up with adding this to the application_helper.rb:
module ApplicationHelper
String.class_eval do
def all_caps_and_reverse
self.upcase.reverse
end
end
end
Now just call the method on any string in the app:
#string = 'This is a string.'
#string.all_caps_and_reverse
.gnirts a si sihT
You won't find any easy way to do this across your whole application for all (or even most) helpers.
Helpers are structured as modules meant to be included in view rendering classes. To leverage them, you'd have to keep a copy of an ActionView around (not a HUGE deal I suppose).
You can always open up the classes and specify each helper you want, though:
class Time
def time_ago_in_words
ActionView::Base.new.time_ago_in_words self
end
end
>> t = Time.now
=> Tue May 12 10:54:07 -0400 2009
>> t.time_ago_in_words
=> "less than a minute"
(wait a minute)
>> t.time_ago_in_words
=> "1 minute"
If you take that approach, I recommend caching the instance of ActionView::Base that you use. Or, if you don't want to go so heavyweight, you can create your own class to just include the helpers you want (you don't want to include the helpers directly in each Time, Date, String, etc, class, though, as that will clutter up the method namespace pretty fierce -- and conflict with the natural names you want).
If you are using Ruby 2.1 you can use Refinements. They are an alternative to monkey-patching Ruby's classes. to borrow #Jarrod's monkey-patch example:
module MyString
refine String do
def all_caps_and_reverse
upcase.reverse
end
end
end
You can now use this in any object you want:
class Post
using MyString
end
#post.title.all_caps_and_reverse
You can read more about Refinements here.
Make a model, TimeAgo or something similar. Implement following this idea here:
a code snippet for "wordifying" numbers
Then, in your controller, create the instance variables using this class. Then, in your view, call #from_time.in_words