[] method of Ruby String - ruby-on-rails

When I reading source code of Beast, I found a lot of code like this:
<%= 'Password'[:password_title] %>
It seems like a call to [] method with Symbol as input parameter to a String to me, but I didn't find such type of parameter of String [] method in the ruby API. What is this means?
thanks in advance.

It's a method added by the "Gibberish" plug-in Beast uses, for internationalization. Remember, classes in Ruby are open, so you can't always count on the standard API in cases like this!

In beast source, check out the gibberish plugin where String class is being modified to accept symbols in brackets function.
String class by itself does not do anything reasonable by applying str[symbol] method.

str[fixnum] => fixnum or nil
str[fixnum, fixnum] => new_str or nil
str[range] => new_str or nil
str[regexp] => new_str or nil
str[regexp, fixnum] => new_str or nil
str[other_str] => new_str or nil
These are what I found. If the symbol here is equals to String, I still don't understand the meaning of the code. Why not simply use:
<%= 'password' %>
or even:
password

Related

How can I extract a Summoner Name from a JSON response?

I'm playing around with with external APIs from League of Legends. So far, I've been able to get a response from the API, which returns a JSON object.
#test_summoner_name = ERB::Util.url_encode('Jimbo')
#url = "https://na.api.pvp.net/api/lol/na/v1.4/summoner/by-name/#{#test_summoner_name}?api_key=#{RIOT_API_KEY}"
response = HTTParty.get(#url)
#summoner = JSON.parse(response.body)
#summoner_name = #summoner[:name]
The JSON object looks like this:
{"jimbo"=>{"id"=>12345678, "name"=>"Jimbo", "profileIconId"=>1234, "revisionDate"=>123456789012, "summonerLevel"=>10}}
So, I'm able to output the JSON object with my #summoner variable in my view. But when I try to output my #summoner_name variable, I just get a blank string.
For reference, this is my view currently:
Summoner Object: <%= #summoner %><br>
Summoner Name: <%= #summoner_name %>
Any help would be greatly appreciated. I've been stumbling through this process all day now.
Problem
You don't have the hash you think you do. Once you've parsed your JSON, your #summoner instance variable actually contains everything else wrapped under a hash key named jimbo. For example, when using the awesome_print gem to pretty-print your hash, you will see:
require 'awesome_print'
ap #summoner, indent: 2, index: false
{
"jimbo" => {
"id" => 12345678,
"name" => "Jimbo",
"profileIconId" => 1234,
"revisionDate" => 123456789012,
"summonerLevel" => 10
}
}
Solution
To get at the name key, you have to go deeper into the hash. For example, you can use Hash#dig like so:
#summoner_name = #summoner.dig 'jimbo', 'name'
#=> "Jimbo"
If you're using an older Ruby without the Hash#dig method, then you can still get at the value by specifying a sub-key as follows:
#summoner_name = #summoner['jimbo']['name']
#=> "Jimbo"
It migth help if you look your json like this:
{"jimbo"=>{
"id"=>12345678,
"name"=>"Jimbo",
"profileIconId"=>1234,
"revisionDate"=>123456789012,
"summonerLevel"=>10}
}
Then you could just do
#summoner_jimbo_name = #summoner['jimbo']['name']
to get the value:
Jimbo

Query mongoid string with brackets

I have mongoid field 'value' as string like "Sivatha (St. 329)", and I use regex for querying the value via ajax as the following:
Street.any_of({ :value => /.*#{params[:q]}.*/i }))
It raises errors while my params value is "Sivatha (St." while I am typing, and It doesn't return result at all when I have exact value "Sivatha (St. 329)".
Can anybody here give me some suggestions? Thanks.
You should be quoting strings with Regexp.quote before interpolating them into a regex:
:value => /.*#{Regexp.quote(params[:q])}.*/i
You don't need the leading and trailing .*, they don't do anything for you, so you could just say:
:value => /#{Regexp.quote(params[:q])}/i
If you weren't using a case-insensitive regex then you could use Regexp.union to quote and regex-ify your string all at once:
:value => Regexp.union(params[:q])
but there's no clean way to add the /i option to that so /#{Regexp.quote(params[:q])}/i is probably the cleanest thing you can do.

Encoding UTF-8 in Rails form parameter name

I'm having a problem with my params.
I'm receiving the following parameters:
{"utf8"=>"✓", "authenticity_token"=>"...=", "Portugu\xC3\xAAs"=>{"title"=>"313" } }
In my controller I need to use the key => "Portugu\xC3\xAAs", but first I need it to be in the right form (that is -> Português) and I don't know how can I do that.
EDIT:
Workflow
1. The user saves a language
2. I use that language in a form to save information, like this:
Português[title]
3 . Because the user can have multiple locales in that form (all the locales saved in step 1)
locales.each do |locale|
...
:value => params[locale.key][:title]
The problem is that locale.key ('Português') doesn't match with "Portugu\xC3\xAAs" so it crashes with nil
Can you help me with this?
Thank you
I've tried this, and the result is good:
<% p = {}
p["Português"] = {}
p["Português"][:title] = "Title in Portugês" %>
<p><%= p["Portugu\xC3\xAAs"][:title] %>
And I get
<p>Title in Portugês</p>
I don't see the problem.
The solution that worked for me was iterating the received params and with the help of URI.escape compare the string, if matches enc_locale is set and used in the value.
Thanks to everyone that helped!
enc_locale = ""
params.each do |param|
if URI.escape(param[0]) == URI.escape(locale.key)
enc_locale = param[0]
end
end
...
:value => params[enc_locale][:title]

String concatenation not possible?

So over the last 2 hours, I've been trying to fill a combobox with all my users. I managed to get all firstnames in a combobox, but I want their full name in the combobox. No problem you would think, just concatenate the names and you're done. + and << should be the concatenation operator to do this.So this is my code:
<%= collection_select(:user, :user_id, #users, :user_id, :user_firstname + :user_lastname, {:prompt => false}) %>
But it seems RoR doesn't accept this:
undefined method `+' for :user_firstname:Symbol
What am I doing wrong?
What you need to do is define a method on the User model that does this concatenation for you. Symbols can't be concatenated. So to your user model, add this function:
def name
"#{self.first_name} #{self.last_name}"
end
then change the code in the view to this:
<%= collection_select(:user, :user_id, #users, :user_id, :name, {:prompt => false}) %>
Should do the trick.
This isn't really rails giving you an error, it's ruby. You're trying to combine the symbols :user_firstname and :user_lastname
A symbol is a variable type, just like integer, string, or datetime (Well technically they're classes, but in this context we can think of them as variable types). They look similar to strings, and can function similarly to them, but there is no definition for the behavior of symbol concatenation. Essentially you're trying to send the method user_firstnameuser_lastname which is just as non-sensical as trying to concat two Symbols.
What you need to understand is that this parameter is looking for a method on your User object, and it won't understand the combination of two symbols. You need to define a method in your model:
def fullname
[user_firstname, user_lastname].reject{|v| v.blank?}.join(" ")
end
This'll return your first + last name for you, and then in the parameter you should send :fullname (because that's the method it'll call on each user object in the collection):
<%= collection_select(:user, :user_id, #users, :user_id, :fullname, {:prompt => false})%>
Also, it's considered poor practice to prefix every single column with the table name. user.user_firstname just looks redundant. I prefer to drop that prefix, but I guess it's mostly up to personal preference.
The arguments for value and display attribute are method names, not expressions on a user object.
To control the format more precisely, you can use the select tag helper instead:
select("user", "user_id", #users.each {|u| [ "#{u.first_name u.last_name}", u.user_id ] })
The docs are pretty useful.

Rails escape_javascript creates invalid JSON by escaping single quotes

The escape_javascript method in ActionView escapes the apostrophe ' as backslash apostrophe \', which gives errors when parsing as JSON.
For example, the message "I'm here" is valid JSON when printed as:
{"message": "I'm here"}
But, <%= escape_javascript("I'm here") %> outputs "I\'m here", resulting in invalid JSON:
{"message": "I\'m here"}
Is there a patch to fix this, or an alternate way to escape strings when printing to JSON?
Just call .to_json on a string and it will be escaped properly e.g.
"foo'bar".to_json
I ended up adding a new escape_json method to my application_helper.rb, based on the escape_javascript method found in ActionView::Helpers::JavaScriptHelper:
JSON_ESCAPE_MAP = {
'\\' => '\\\\',
'</' => '<\/',
"\r\n" => '\n',
"\n" => '\n',
"\r" => '\n',
'"' => '\\"' }
def escape_json(json)
json.gsub(/(\\|<\/|\r\n|[\n\r"])/) { JSON_ESCAPE_MAP[$1] }
end
Anyone know of a better workaround than this?
May need more details here, but JSON strings must use double quotes. Single quotes are okay in JavaScript strings, but not in JSON.
I had some issues similar to this, where I needed to put Javascript commands at the bottom of a Rails template, which put strings into jQuery.data for later retrieval and use.
Whenever I had a single-quote in the string I'd get a JavaScript error on loading the page.
Here is what I did:
-content_for :extra_javascript do
:javascript
$('#parent_#{parent.id}').data("jsonized_children", "#{escape_javascript(parent.jsonized_children)}");
Already there is an issue in github/rails
https://github.com/rails/rails/issues/8844
Fix to mark the string as html_safe
<%= escape_javascript("I'm here".html_safe) %>
or even better you can sanitize the string
<%= sanitize(escape_javascript("I'm here")) %>
<%= escape_javascript(sanitize("I'm here")) %>

Resources