Why isn't the args parameter used in ActionController::Instrumentation::render? - ruby-on-rails

I am new to Ruby and to Rails, and am trying to understand fully what I'm reading.
I am looking at some of the Rails source code, in this case action_controller/metal/instrumentation.rb.
def render(*args)
render_output = nil
self.view_runtime = cleanup_view_runtime do
Benchmark.ms { render_output = super }
end
render_output
end
I understand that *args is using the splat operator to collect the arguments together into an array. But after that, it stops making much sense to me.
I can't fathom why render_output is set to nil before being reassigned to equal super and then called with no arguments. I gather that some speedtest is being done, but coming from other languages I'd expect this to just be something more like Benchmark.ms(render_output) or perhaps Benchmark.start followed by render_output followed by Benchmark.end. I'm having a hard time following the way it works here.
But more importantly, I don't really follow why args isn't used again. Why bother defining a param that isn't used? And I mean, clearly it is getting used-- I just don't see how. There's some hidden mechanism here that I haven't learned about yet.

In this context, it is important to note how super works, because in some cases it passes implicitly arguments and you might not expect that.
When you have method like
def method(argument)
super
end
then super is calling the overridden implementation of method implicitly with the exact same arguments as the current method was called. That means in this example super will actually call super(argument).
Of course, you can still define a method call that explicitly sends other arguments to the original implementation, like in this example:
def method(argument)
super(argument + 1)
end
Another important edge-case is when you want to explicitly call super without any arguments although the current method was called with arguments then you need to be very explicit like this
def method(argument)
super() # note the empty parentheses
end

Let me try to describe you what I think this code does.
*args*
is using the splat operator to collect the arguments together into an array
that is totally correct, however they don't use it, and if you will go to master branch, they just changed it to *. Asking why it is defined and not used, I think that's question about bad design. They should have called it _args or at least like it is now just single splat *.
render_output is set to nil because of scopes, it has to be explicitly defined out block, lambda, proc in order to store value in it, otherwise its visibility will be locked only to those lambda, proc, block execution. Refer to this article
Benchmark.start. Blocks are great ruby construction. You are totally correct that speedtest is done, we can see it is just decorator for benchmark library.
source.
You are wondering why we cannot just pass it as Benchmark.ms(render_output), that's because what will be given to benchmark ms function? It will be given result, like <div> my html </div. And how we can measure this string result - no how. That's why we calling super right in this block, we want to access parent class function and wrap it inside block, so we are not calling it, we just construct it, and it will be called inside benchmark lib, and measured execution like
class Benchmark
...
def realtime # :yield:
r0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
yield
Process.clock_gettime(Process::CLOCK_MONOTONIC) - r0
end
...
end
So here we can count realtime of function execution, this is the code from original library

Related

RIght way of writing module methods in Ruby

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.

Ruby error - Undefined Method

I am try to write a function that will find the items in an array which match the string passed to the function. See code below.
class Island
def filter(string)
for element in self
if element.include? (string)
yield(element)
end
end
end
end
list = ["sasha","rory","rob","anthony","andre","tariq","kimberly","antoinette"]
list.filter("an"){|i| puts i}</i>
How i keep getting "undefined method 'filer' for #
I'm not sure what i'm doing wrong.
First let me object against the solution posted by #Sravan :
While it is true - and sometimes even a good solution - to monkey-patch a class, you have to be careful how to do it, because it may become a time bomb:
Ruby evolves, and new versions often add methods to existing classes. This means that if you add a method Array#search, and a new version of Ruby will also add a method of the same name, your new method will SILENTLY override the one in Ruby. You likely won't notice it for long time, until you are using a feature which is supposed to use Rubys Array#search - maybe by using something new in stdlib - and you get weird results. To track down this type of error can be a nightmare. This is exactly the case when you use search as a method name.
Now, how to do it then? Three possibilities:
(1) If you monkey-patch, use at least a method name which is unlikely to become part of the official interface. It might have your project's name as a prefix, or plenty of underscore characters, and so on. Note that this is not 100% foolproof: A later version of Ruby might add under the hood a private method with exactly the same name than the one you were choosing, but of course the odder your name, the less likely this will happen.
(2) If you don't like this idea of using "clumsy" names, you could at least test before defining the new method, whether it already exists, and throw an exception if it doesn't:
class Array
if self.method_defined?(:search)
raise "#{self.class}::search already defined"
else
def search(...)
...
end
end
end
(3) The third possibility is to avoid monkey-patching and keep the method in your Island class. In this case, the method definition would be different:
class Island
def self.filter(array, string)
...
end
end
and it would be called by
Island.filter(myarray, mystring)
UPDATE: Forgot a forth possibility:
(4) You can make Island a subclass of Array. I don't know what else you want to do with your islands, but maybe this is an option worth considering:
class Island < Array
def filter(string)
...
end
end
Of course, when invoking filter, you need to turn your array into an island, before you can use it:
list = Island.new([....])
Following ruby's convention over configuration, you can add/overwrite any method in any class
So, adding a function to array class makes it accessible to all the arrays. So, in this solution.
1) First thing is you have taken the filter function in Island class, instead, you need to take inside Array class since the list is an array.
class Array
def filter(string)
for element in self
if element.include? (string)
yield(element)
end
end
end
end
list = ["sasha","rory","rob","anthony","andre","tariq","kimberly","antoinette"]
list.filter("an"){|i| puts i}
O/P:
anthony
andre
antoinette
2) Since Filter is a keyword as suggested by other answer, take another name for it. Eg: search
class Array
def search(string)
for element in self
if element.include? (string)
yield(element)
end
end
end
end
list.search("an"){|i| puts i}

In ruby how do I write a 'do' method in ruby? [duplicate]

This question already has answers here:
Blocks and yields in Ruby
(10 answers)
Closed 9 years ago.
I keep writing the same pattern of code in Ruby, which seems like it would benefit from a 'do' style bit of code but I'm not sure how to write the method.
I keep doing this pattern of code, which starts and ends with the same lines of code...
x.increment!(:step_count) # same each time
# ...then some different code each
x.update_column(:step_description, "blerg message") # same each time
I feel it would benefit from a 'do' something that would look like this...
update_steps "blerg message" do
# ...then some different code each
end
And then inside the 'do' each time it does the common code.
How would I go about making a method where I can use a 'do'.
Thanks!
Edit: I think it's important to not close this because I didn't know to search for 'block' or 'yield'. People who may no know these terms may end up searching for 'do' instead.
Creating methods that accept a block is one of Ruby's most powerful features.
The common way to define such a method would be:
def foo(*args, &block)
# your code here
yield
# some more code
end
foo do
# This code runs when yield is called
end
There are a few things you should know about the above:
The &block parameter is not required. You can just use yield anyway. But there are a few reasons why you should add it to your method definition:
It makes it clear that your method accepts a block
The & basically transforms the block to a proc object. This could be handy since that way you can actually pass it around as a parameter to another method that accepts a block. You just need to re-apply the & to make it again a block.
Handling a proc object can be more powerful since you can also set its binding.
You can pass arguments to yield. The arguments you pass are the block local variables. For example in:
[1,2,3].each {|x| puts x}
yield is called with one of the array elements on every iteration. Calling yield with an argument is the same as block.call(a) where a is an argument.
If your method encounters a yield and there is no block given it will raise an exception. This might be correct in some cases. But if you want to have a different behavior if no block is given you can use the block_given? method to check it.
&block must be the last parameter in your method definition.
Pass it a block as an argument
def my_method(&block)
do_something_the_same
yield # calls whatever is inbetween "do" and "end"
end
Or you can also do this by calling block.call
def update_steps(&block)
block.call()
end

remote code execution in ruby with constantize

I'm trying to wrap my head around remote code execution vulnerabilities in ruby/rails when contantize is used.
I understand that being able to provide any class name to the server could be potentially dangerous, but I'm wondering if this by itself is dangerous.
for example, if a rails controller code looks something like this (i.e. executes a hardcoded method on the instantiated object):
klass = params[:class].classify.constantize
klass.do_something_with_id(params[:id]) if klass.respond_to?('do_something_with_id')
Is this code vulnerable? Or only in combination with being able to also specify the method to be called on the class?
Turning a string into a constant isn't dangerous in itself, but how that constant is used is potentially dangerous (i.e. the method that is then called).
If you really need to do this, then it's probably best to provide a list of classes that are allowed. E.g.
klass = params[:class].classify
if %w(Class1 Class2 Class3).include? klass
klass.constantize.do_something_with_id(params[:id])
else
raise 'Forbidden'
end
However it's done, it helps you to sleep at night to know that the input is considerably limited.
Update
Another way of controlling the creation, which is more explicit but also more verbose, is to use a case statement:
def create_klass(option)
case option
when "option1"
Class1
when "option2"
Class2
when "option3"
Class3
else
raise "Unknown option"
end
end
This way, you don't need to expose the internals of your system to the client. If there are many options, then you could use a hash with options mapping to classes.

When blocks are more useful than functions (ruby)?

I have two examples that give the same result.
With block:
def self.do_something(object_id)
self.with_params(object_id) do |params|
some_stuff(params)
end
end
def self.with_params(object_id, &block)
find_object_by_id
calculate_params_hash
block.call(params_hash)
end
and with method:
def self.do_something(object_id)
some_stuff(self.get_params(object_id))
end
def self.get_params(object_id)
find_object_by_id
calculate_params_hash
params_hash
end
The second solution seems more straightforward, but I found some usages of the first one in our application code. My question is: in which situation the first one is recommended? What are the pros and cons of each one?
Normally people use blocks when they want to run a piece of code inside of another piece of code. Examples:
DB.with_shard_for_user(user_id) do |db|
# perform operations on a user's shard
end # shard is reverted back to original value
File.new(filename) do |file|
# work with file
end # file is closed automatically
User.transaction do
# run some operations as a single transaction
end
These blocks are closed on their lexical context (they capture variables from where the block is declared, and carry them over to the place when blocks are called).
Schematic structure of a method that accepts a block.
def transaction
open_transaction # pre- part
yield if block_given? # run provided code
commit_transaction # post- part
rescue
rollback_transaction # handle problems
end
In your first example, use of a block is probably unjustified (IMHO). Too complex for no apparent reason.
The main difference between a block and function as per your example is that the block runs within the context of the calling function.
So if your example was as:
def self.do_something(object_id)
x = "boogy on"
self.with_params(object_id) do |params|
some_stuff(params)
puts x
end
end
The code within the block can access the variable x that was defined outside the block. This is called a closure. You couldn't do this if you were just calling a function as per your second example.
Another interesting thing about blocks is they can affect the control flow of the outer function. So it is possible to do :
def self.do_something(object_id)
self.with_params(object_id) do |params|
if some_stuff(params)
return
end
end
# This wont get printed if some_stuff returns true.
puts "porkleworkle"
end
If the some_stuff call within the block returns a true value, the block will return. This will return out of the block and out of the dosomething method. porkleworkle would not get output.
In your examples you don't rely on either of these, so using function calls is probably much cleaner.
However, there are many situations where using blocks to allow you to take advantage of these things is invaluable.
When you call with_params(), you are not only sending in data, you are also providing some code to run. See if different blocks are sent into the with_params() call:
...
self.with_params(object_id) do |params|
some_other_stuff()
some_stuff(params)
end
...
and somewhere else:
...
self.with_params(object_id) do |params|
even_more_stuff(params)
end
...
If the blocks are all the same or with_params() is just called from one place then you might consider eliminating the blocks.
To sum up: use blocks if you want to pass into the method different bits of code(blocks) as well as data: hey with_params, take this data(object_id) and, by the way, run this code(block) while you're at it.
BTW you are doing different things in the two examples: with_params() returns
some_stuff(params_hash)
after evaluating the block. And get_params() just returns
params_hash
A block totally rely on your code, but a function has its own code.
So, if your code varies situation by situation, use block.
If not, build a function and use it as a block box.

Resources