How to transform a user input in rails 4? - ruby

I am creating an app where users could enter their name that will be returned as chemical symbols (when matching).
So I managed to do in the console like:
symbols = {
"ac" => "Ac",
"al" => "Al",
"am" => "Al",
"br" => "Br",
"ba" => "Ba",
"cr" => "Cr"
}
puts "Get your chemical name!"
name = gets.chomp
name.gsub!(/#{symbols.keys.join('|')}/, symbols)
puts name
Now I'd like to make it works in the app but I don't know how to create the method ?
I want it to be displayed only in the views/show
= #convertor.name
= link_to 'Edit', edit_convertor_path(#convertor)
= link_to 'Back', convertors_path
shall I create the method in my model or else where?
class Convertor < ActiveRecord::Base
def get_chemical_name(name)
symbols = {
"ac" => "Ac",
"al" => "Al",
"am" => "Al",
"br" => "Br",
"ba" => "Ba",
"cr" => "Cr"
}
name.gsub!(/#{symbols.keys.join('|')}/, symbols)
puts name
end
end
so in my view showI tried something like =#convertor.get_chemical(name) but unsuccessful..
I need your help please

Yes, the method can stay in the model.
Short one:
#convertor.get_chemical(#convertor.name)
would work but this is not a right way to do that.
Correct way would be to change the method in Convertor class to not accept any arguments, since it is an instance method and it already has access to name attribute. So, after changing the method signature
def get_chemical_name
symbols = {
"ac" => "Ac",
"al" => "Al",
"am" => "Al",
"br" => "Br",
"ba" => "Ba",
"cr" => "Cr"
}
name.gsub!(/#{symbols.keys.join('|')}/, symbols)
end
you will be able to use
=#convertor.get_chemical_name
Also, I removed useless puts name from the method definition - in Ruby the last evaluated line is already a return value of the method (unless returned before the end of the method).
Also, if by any chance you are using the symbols hash anywhere else, you can move it to constant.

Related

How to merge values of a single hash?

Is there any way to merge values of a single hash?
Example:
address = {
"apartment" => "1",
"building" => "Lido House",
"house_number" => "20",
"street_name" => "Mount Park Road",
"city" => "Greenfield",
"county" => nil,
"post_code" => "WD1 8DC"
}
Could we get an outcome which looks like this?
1 Lido House,
20 Mount Park Road,
Greenfield,
WD1 8DC
address.compact will remove the value which equals nil, but what if in a method you include string interpolation and you want to exclude the nil value for some addresses and include it for others without a comma at the end?
def address(hash)
hash.compact
puts "#{hash["apartment"]} #{hash["building"]}, \n#{hash["house_number"]} #{hash["street_name"]}, \n#{hash["city"]}, \n#{hash["county"]}, \n#{hash["post_code"]}"
end
You need to join the values in a string:
"#{address['house_number']} #{address['street_name']},\n#{address['city']},\n#{address['post_code']}"
You could also improve the formatting by making this a helper method, and using a HEREDOC:
def formatted_address(address)
<<~ADDRESS
#{address['house_number']} #{address['street_name']},
#{address['city']},
#{address['post_code']}
ADDRESS
end
Usage:
address = {
"house_number" => 20,
"street_name" => "Mount Park Road",
"city" => "Greenfield",
"post_code" => "WD1 8DC"
}
puts formatted_address(address)
# => 20 Mount Park Road,
# Greenfield,
# WD1 8DC
Use string formats.
"%{house_number} %{street_name},\n%{city},\n%{post_code}" % address

Change deep_merge to Utils.deep_merge_hashes

I am using Octopress to generate static html pages. I tried to change the language of the dates using this instruction (it is in German but we need only the code). When I copy date.rb from this German website to my octopress/plugins, I have the following error: Liquid Exception: undefined method `deep_merge' for # in blog/path/to/post/index.html.
I can generate site if I comment out this part in date.rb:
def to_liquid
date_format = self.site.config['date_format']
self.data.deep_merge({
"title" => self.data['title'] || self.slug.split('-').select {|w| w.capitalize! || w }.join(' '),
"url" => self.url,
"date" => self.date,
# Monkey patch
"date_formatted" => format_date(self.date, date_format),
"updated_formatted" => self.data.has_key?('updated') ? format_date(self.data['updated'], date_format) : nil,
"id" => self.id,
"categories" => self.categories,
"next" => self.next,
"previous" => self.previous,
"tags" => self.tags,
"content" => self.content })
end
Then the language is changed for the dates in blog/archives, but not for the dates in posts. I found a similar problem which has been solved by changing deep_merge → Utils.deep_merge_hashes. So I understand that I need to do exactly the same in the piece of the code I presented above. I think it should be quite easy, but since I don't know Ruby, I didn't succeed yet. Could you please tell me how should I use Utils.deep_merge_hashes instead of deep_merge in this case?
This works (ruby 2.1.1 - Jekyll 2.5.3)
def to_liquid(attrs = nil)
date_format = self.site.config['date_format']
new_datas = {
"title" => self.data['title'] || self.slug.split('-').select {|w| w.capitalize! || w }.join(' '),
"url" => self.url,
"date" => self.date,
# Monkey patch
"date_formatted" => format_date(self.date, date_format),
"updated_formatted" => self.data.has_key?('updated') ? format_date(self.data['updated'], date_format) : nil,
"id" => self.id,
"categories" => self.categories,
"next" => self.next,
"previous" => self.previous,
"tags" => self.tags,
"content" => self.content }
Utils.deep_merge_hashes(self.data, new_datas)
end

rails + activerecord: how create a hash from table with particular field's value as key

Given a table ZipCodeInfos with fields zipcode, state, city (all strings), where zipcode is unique:
zipcode,city,state
"10000", "Fooville", "AA"
"10001", "Smallville", "AA"
"10002", "Whoville", "BB"
What is the fastest way to generate a hash object of the entire table where the zipcode is a key like this:
{ "10000" => {:city => "Fooville", :state => "AA" },
"10001" => {:city => "Smallville", :state => "AA" },
"10002" => {:city => "Whoville", :state => "BB" } }
I know for a given record I can use .attributes to generate a hash with key,value pairs of field-names, field-values, for example Zipcode.first.attributes gives me
{"id" => 1, "zipcode" => "10000", "city" => "Fooville", "state => "AA" }
But, short of brute force iterating over each record (via .map), I cannot quite figure out how to create the desired hash with the zipcode as the key for each node of the hash.
This is the best I could come up with, and I suspect there is some nifty Ruby goodness that is faster?
zip_info_hash = {}
ZipCodeInfo.all.map{|x| zip_info_hash[x.zip] =
{'state' => x.state, 'city' => x.city }}
You could also try:
ZipCodeInfos.all.group_by &:zipcode
will get you a hash of zip code to array of ZipCodeInfos activerecords.
You can use inject method.
Here is what I generally use.
def visitors_name_email
visitors.inject({}) do |result, visitor|
result.merge(visitor.name => visitor.email)
end
end
I can't think of a way to avoid map here. I'd make only some minor changes to your code:
zip_info=Hash[*ZipCodeInfo.all
.map{|x| [x.zip, {:city => x.city, :state => x.state}]}
.flatten]

Ruby: Loop through hash and check if a key exists to determine markup and data to be displayed

This is my first time working with Ruby, so I may be approaching this incorrectly.
I am trying to go through a hash to display it's contents. As I'm going through the hash I'll need to test if a key exists, like city. If city doesn't exist then it shouldn't display the address. This is where I've started with building my hash:
# app.rb
set :haml, :format => :html5
get "/" do
#users = Hash[
[["name", "bill"], ["city", "nyc"], ["address", "street"]],
[["name", "ted"], ["city", "denver"]],
[["name", "sam"], ["address", "road"]]
]
haml :index
end
And this is how I am looping through the hash:
# layout.haml
- #users.each do |user|
- user.each do |u|
- u.each do |b|
= b
Once I get to b it will display all of the content like so:
["name", "bill"]
["city", "nyc"]
["address", "street"]
["name", "ted"]
["city", "denver"]
In the loop, how can I display the name as well as check to see if the address exists for each user to determine if the city should be displayed as well as any markup that may need to be added? It would ideally display something like:
<p>bill, <span class="address">nyc, street</span></p>
<p>ted</p>
<p>sam, <span class="address">road</span></p>
Am I creating the Hash properly to do it this way?
Instead of what you are trying to do with nested arrays inside a hash, it would be better to have an array that contains user hashes:
#users = [
{ :name => 'bill', :city => 'city', :address => 'street' },
{ :name => 'ted', :city => 'denver' },
{ :name => 'sam', :address => 'road' }
]
With that, you can do something like this:
- #users.each do |user|
= user[:name]
- if user.has_key?(:address) && user.has_key?(:city)
= "#{user[:address]}, #{user[:city]}"
- elsif user.has_key?(:address)
= "#{user[:address]}"

Parsing text using Ruby

I have the following text which will always follow the same format:
1
"13"
"241"
"Rabun"
"06"
"County"
2
"13"
"281"
"Towns"
"06"
"County"
I would like to assign each section to a hash like:
locality= {:id => "", :fips1 => "", :fips2 => "", :county => "", :stateid => "", :type => ""}
How would I go about doing this in Ruby? Any help is greatly appreciated.
fields = [:fips1,:fips2,:county,:stateid,:type]
arraywithhashes = yourtextdata.split("\n\n").map { |loc|
Hash[
[[:id,loc[/\d+/]]] +
fields.zip(loc.scan(/"([^"]+)"/).map &:first)
]
}
If you add new fields to your file, the only you'll need to edit is to add it to fields.
for each section, use a regular expression with groups corresponding to each entry in the section, then simply create hash table as you described from these groups.
locality.each_key { |k| locality.store(k, "foo") }
Another newbie-ish person here, but that might be a start for you.
You might want to consider using a Struct instead of a Hash.
Locality = Struct.new(:id, :fips1, :fips2, :county, :stateid, :type)
localities = []
DATA.each_slice(7) do |chunk|
chunk.pop if chunk.size == 7
localities << Locality.new(*chunk.map{|line| line.scan(/\w+/) })
end
p localities # => [#<struct Locality id=["1"], fips1=["13"], fips2=["241"], etc.
puts localities[1].fips2 # => 281
__END__
1
"13"
"241"
"Rabun"
"06"
"County"
2
"13"
"281"
"Towns"
"06"
"County"
each_slice(7) takes 7 lines of
DATA (the stuff after __END__ ).
The last line is removed unless there
are only six lines (the last
'record').
A cleaned-up copy of the remaining
lines is made. With these values a
new Locality is created and added to
an array

Resources