Query mongoid string with brackets - ruby-on-rails

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.

Related

How to parse key name with name(value) pairs into hash of key/value pairs with original value?

I have a large hash like this:
{"id"=>"1",
"contact_id"=>"15062422",
"status"=>"Complete",
"[question(12), option(24), piped_page(32]" => "Yes",
"[question(13), option(32)]" => "Robert",
"[question(14)]" => "Thing"}
I need to parse the keys that start with '[' to separate the name(value) pairs. The number of names (i.e. question, option, etc) in each key is variable but there are a known number of possibilities.
I'd like to convert each pair into a new has like this:
{:question => 12, :option => 24, :piped_page => 32, :value => "Yes"}
I've thought of using .to_s on each hash element and then doing a variety of string substitutions followed by eval, but the .to_s escapes the double quotes which really complicates things.
Any ideas?
You can use regex to solve it:
str = "[question(12), option(24), piped_page(32)]"
Hash[str.scan /(\w+)\((\w+)\)/]
=> {"question"=>"12", "option"=>"24", "piped_page"=>"32"}

Simple Form - Translating options of a input field

I'm trying to use the i18n feature of simple form, which works great in most cases.
My only problem is, that in one case I want to use numbers as option values, so I can not simply create a symbol like in the other cases. Right now, I'm using this solution:
f.input :adm, :as => :select, :collection => [[:adm11 ,"11"],
[:adm00, "00"], [:adm06, "06"], [:adm99, "99"]]
Can I somehow make simple_form look up adm11 and so on in the usual way, so I can keep a sensible structure in my translation file?
I know I could do it with standard ruby i18n, but I'm looking for a better way.
f.input :adm,
:collection => [[:adm11 ,"11"], [:adm00, "00"], [:adm06, "06"],
[:adm99, "99"]],
:label_method => lambda { |el| t "define.i18n.keys.here.#{el.first}" }
I think you can't do it because of this line in SimpleForm:
collection_translated = translate_collection if collection_classes == [Symbol]
So it means that SimpleForm translates options if it's array of symbols. See discussion here https://github.com/plataformatec/simple_form/pull/302

Explaining hashes in Ruby

I'm reading a book Crafting Rails Applications by Jose Valim and have come across something that I don't understand. I'm wondering if someone can explain the difference in plain English between the three types of hash below.
For example, in what way is the nested hash (as its represented in this example) a nested hash. In other contexts, I understand nested hashes, but don't get it here.
In what way is an "array" a "key" in the second example. To me it looks just like an array with four variables.
In what way is the third example a hash with "hash as key".
Nested hash
#cached[key][prefix][name][partial]
Simple hash with array as key
#cached[[key, prefix, name, partial]]
Simple hash with hash as key
#cached[:key => key, :prefix => prefix, :name => name, :partial => partial]
The nested hash, is well, a nested hash. The example given, #cached[key][prefix][name][partial], is showing you the "path" to a particular value, so in this case the hash might look something like this:
#cache = {
key => {
prefix => {
name => {
partial => "value"
}
}
}
}
For the simple hash with an array as a key, they're using that 4-element array as one of the keys in the hash.
#cache = {
[key, prefix, name, partial] => "value",
another_key => "another value"
}
For the simple hash with hash as a key, they're using that hash (note that the {}'s for the hash are optional, which may cause some confusion) as one of the keys in the hash.
#cache = {
{:key => key, :prefix => prefix, :name => name, :partial => partial} => "value",
another_key => "another value"
}
Hope that helps!
A hash simply associates key objects to value objects. The keys and values can be anything.
If a value object is itself a hash, you could call it a "nested hash" because in some sense it is inside the main hash.
If a key object is an array, then you get a "hash with array as key".
If a key object is itself a hash, then you get a "hash with hash as key".
See amfeng's answer for a good visual representation of these different cases.
You will need to be somewhat familiar with Ruby syntax to identify the different cases when you see them.
For example, to understand #cached[[key, prefix, name, partial]] you need to know that [key, prefix, name, partial] represents an array, so what you have is like #cached[array], which means an array is being used as a key.
When you see something like #cached[key][prefix] you should know that it is equivalent to (#cached[key])[prefix] so the value object (#cached[key]) is some sort of object that responds to the [] method. In this case, it is a nested hash because the author told you so, but if you didn't know that context then it is possible for it to be something else.
When you see something like #cached[:key => key, :prefix => prefix, :name => name, :partial => partial] you should know it equivalent to #cached[{:key => key, :prefix => prefix, :name => name, :partial => partial}], which means we are using as hash as a key.

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.

[] method of Ruby String

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

Resources