Ruby: How do you have optional first arguments? but default trailing arguments? - ruby

I'd like to have a method that is similar to this:
def method_with_optional(..., user = current_user, account = current_account)
...
because, I don't want to have to pass in current_user, and current_account every time.
but as long as a user object isn't passed, the user formal parameter shouldn't be over-ridden.
This way I could do the following
method_with_optional(params[:id])
or
method_with_optional(params[:id], User.new)

What you're looking for are named arguments, which is not supported in Ruby 1.8, but you may have some success with arguments.

Sorry, at the moment there is no built-in support for named parameters, you have to wait for Ruby 2.0.

An alternative to default arguments would be to assign the variable in the body of the method and to provide the User, Account arguments as a part of the params hash. You can check to see if the params contains a User and/or Account and then do the needful:
user = params[:user] || current_user
account = params[:account] || account
EDIT: If you cannot add things to the Params hash before invoking the method, then I don't know what you can do other than re-order the formal parameters in the method signature :)

Related

How to use the variable in one action to another action

In the ruby controller, I have two methods in the same controller.
class NotificationsController < ApplicationController
def first
variable_one = xxxx
end
def second
// do something
end
end
I want to use the variable one in the method first, and use it in the method two. I tried to assign the variable one to a session hash. session[:variable_one] = variable_one, and access it in the method two. But it turns out the session[:variable_one] in the method two is nil. These two methods don't have the corresponding views, so I cannot add a link_to and pass parameters. The method one cannot be set as before_action as well.
Could you please have some suggestions on this problem? Thanks so much.
The issue that session is stored via cookie, and therefore it is specific to one device. So, you will have one session between the rails app and your frontend, and another session betweeen the rails app and Twilio (probably the Twilio session will reset between each request). Basically, they're totally separate contexts.
Possibly you could figure out how to pass the information along via Twilio - see https://www.twilio.com/docs/voice/how-share-information-between-your-applications - but as a general-purpose workaround, you could just store the column on the database.
First, make a migration to add the column:
add_column :users, :my_variable, :string
Set this value in the first endpoint:
def first
current_user.update my_variable: "xxxx"
end
Then read it from the second:
def second
# first you would need to load the user, then you can read the value:
my_variable = current_user.my_variable
# you could set the db value to nil here if you wanted
current_user.update my_varible: nil
end

Pass input parameters to ruby-written shell?

I'm trying to write a shell in Ruby (using readline), implementing some custom commands. To create the correspondence between given input and methods that are defined in an external module I'm using an hash like this
hash = {
'command_1' => method(:method_1),
'command_2' => method(:method_2)
}
And once I got the user input I pass it to the hash calling the method associated with the command-key
hash[input.to_s].()
My questions are: how can I handle variants of the same command? (e.g. for the help command give different output depending if a flag is given, something like help -command_1)
How can I pass parameters to methods in the hash? (e.g. pass to an open command the file to be opened like open file_name)
Thanks to all in advance.
While that might work if you wrangle it enough, the easy way is this:
hash = {
'command_1' => :method_1,
'command_2' => :method_2
}
send(hash[input.to_s])
The send method allows dynamic dispatch which is way easier than trying to deal with method.

Passing Boolean value as a String to a method expecting a String

In Ruby, I'm attempting to pass a boolean result to a method which accepts as a string as a parameter. This is as an experiment.
fileexists = File.file?("#{$fileLocation}")
puts File.file?("#{$fileLocation}")
puts fileexists
puts fileexists.to_s
This will result in:
true
true
true
Now if I attempt to call a method which accepts a string and pass this parameter in a number of ways.
slack(message: "#{fileexists}")
Results in the error message.
'message' value must be a String! Found TrueClass instead.
Which confuses me as I understand that Ruby evaluates anything within "" as a String. So placing a TrueClass object within a placeholder, should effectively cast this value to a string.
So let's try something slightly different:
slack(message: "#{fileexists.to_s}")
This results in the same error.
'message' value must be a String! Found TrueClass instead.
Now this is where things GET REALLY WEIRD!!
slack(message: "#{fileexists.to_s} ")
slack(message: "#{fileexists} ")
If I add a single bit of whitespace to the end of the string after the placeholder, it passes, and a slack message is sent my way, displaying 'true'.
I understand I may be asking for a bit of 'Crystal-ball' insight here as
I don't have the implementation of the 'slack' method, and this may be a result of the way that's implemented.
Does Ruby check types of params as they're passed like this?
Is that a Ruby standard error message you might receive, or a custom error thrown by the slack() method?
The dependency you are using, fastlane, auto-converts values that are passed into the actions (your call to slack).
The reason for this is that parameters in fastlane can also be specified via the commandline, so conversion is necessary. It converts your value of "true" to a boolean automatically because there is no Boolean class in ruby and the type of parameters is specified by giving it the name of a class, so it automatically converts "true" to a boolean. The offending line in the code is here.
As you can see in the code above, a workaround would be to do slack(message: "#{fileexists.to_s.capitalize}") or slack(message: fileexists ? "t" : "f"). Anything really as long as you avoid yes, YES, true, TRUE, no, NO, false, and FALSE
I understand I may be asking for a bit of 'Crystal-ball' insight here as I don't have the implementation of the 'slack' method, and this may be a result of the way that's implemented.
Sounds like youre using a lib (gem) which contains the methods slack, you can check the gem code location running gem which gem_name on your console.
Does Ruby check types of params as they're passed like this?
No
Is that a Ruby standard error message you might receive, or a custom error thrown by the slack() method?
Custom Error
As Jorg W Mittag stated this looks like a misimplementation of slack method when trying to deserialize, and then checking the types. You could fix the slack method on the gem by contributing to this gem, monkeypatch it or you can try to hack it the way it is... this last onde depends on how slack was implemented, maybe adding an extra pair of quotes, like "\"#{fileexists}\""
PS: You don't have to embbed the string inside another string if you're going to use it as it is, like fileexists = File.file? $fileLocation , this should work.
I'm only guessing here because we don't know what the method definition of slack is expecting an un-named String, but you're passing a hash.
slack(fileexists.to_s)

How to pass variable to DB.from in Sequel?

I'm just starting to use Sequel in Ruby, and like it alot.
I want to pass a variable to the "from" method. So instead of calling a method like so:
DB.from(:items)
I'd like to call the method with a variable. For example:
# both of the following approaches fail
tableName = "items"
DB.from(tableName)
DB.from(:tableName)
But it fails with a sql error about a value that's not in my variable. I don't think this is a Sequel issue... I think it's a "I'm new to Ruby" issue.
How can I pass a variable to the from method above?
Do as below using String#to_sym method :
DB.from(tableName.to_sym)
Looking at the documentation of Sequel::Database#from, it seems it accepts all arguments as symbols. Thus you need to convert the string object pointed by the local variable tableName, to a symbol object.

PageObject with Ruby - set text in a text field only works in the main file

I'm automating a site that has a page with a list of options selected by a radio button. When selecting one of the radios, a text field and a select list are presented.
I created a file (test_contracting.rb) that is the one through which I execute the test (ruby test_contracting.rb) and some other classes to represent my page.
On my class ContractPage, I have the following element declaration:
checkbox(:option_sub_domain, :id => "option_sub_domain")
text_field(:domain, :id => "domain_text")
select_list(:tld, :id => "domain_tld")
I've created in the ContractPage a method that sets the configuration of the domain like this:
def configure_domain(config={})
check_option_sub_domain
domain = config[:domain]
tld = config[:tld]
end
When I call the method configure_domain from the test_contracting.rb, it selects the radio button, but it doesn't fill the field with the values. The params are getting into the method correctly. I've checked it using "puts". Even if I change the params to a general string like "bla" it doesnt work. The annoying point is that if on test_contracting.rb I call the exact same components, it works.
my_page_instance = ContractPage.new(browser)
my_page_instance.domain = "bla"
my_page_instance.tld = ".com"
What I found to work was to in the configure_domain method, implement the following:
domain_element.value = config[:domain]
tld_element.send_keys config[:locaweb_domain]
Then it worked.
The documentation for the PageObjects module that I'm using as reference can be found here: http://rubydoc.info/github/cheezy/page-object/master/PageObject/Accessors#select_list-instance_method
Do you guys have any explation on why the method auto generated by the pageobject to set the value of the object didnt work in this scope/context ?
By the way, a friend tried the same thing with Java and it failed as well.
In ruby all equals methods (methods that end with the = sign) need to have a receiver. Let me show you some code that will demonstrate why. Here is the code that sets a local variable to a value:
domain = "blah"
and here is the code that calls the domain= method:
domain = "blah"
In order for ruby to know that you are calling a method instead of setting a local variable you need to add a receiver. Simply change your method above to this and it will work:
def configure_domain(config={})
check_option_sub_domain
self.domain = config[:domain]
self.tld = config[:tld]
end
I'm pretty new to this world of Selenium and page objects but maybe one of my very recent discoveries might help you.
I found that that assignment methods for the select_list fields only worked for me once I started using "self" in front. This is what I have used to access it within my page object code. e.g., self.my_select_list="my select list value"
Another note - The send_keys workaround you mention is clever and might do the trick for a number of uses, but in my case the select list values are variable and may have several options starting with the same letter.
I hope something in here is useful to you.
UPDATE (Jan 3/12)
On diving further into the actual Ruby code for the page object I discovered that the select_list set is also using send_keys, so in actuality I still have the same limitation here as the one I noted using the send_keys workaround directly. sigh So much to learn, so little time!

Resources