Refactoring a hash to Object - ruby-on-rails

I have a method that return a Hash and then I write the entries of hash in xml file. Iwant to convert this Hash to an object to store the entry and then write it to xml file...
My current code is like this
def entry(city)
{
:loc => ActionController::Integration::Session.new.url_for(:controller => 'cities', :action => 'show', :city_name => city.name, :host => #country_host.value),
:changefreq => 0.8,
:priority => 'monthly',
:lastmod => city.updated_at
}
end
The write_entry method is inside my writer class that writes this entry to xml file
def write_entry(entry)
url = Nokogiri::XML::Node.new( "url" , #xml_document )
%w{loc changefreq priority lastmod}.each do |node|
url << Nokogiri::XML::Node.new( node, #xml_document ).tap do |n|
n.content = entry[ node.to_sym ]
end
end
url.to_xml
end
Thanks

I might be way off here, but it seems like what you're trying to do is something like this:
First, figure out what makes sense as a class name for your new object. I'm going with Entry, because that's the name of your method:
class Entry
end
Then take all the "properties" of your hash and make them reader methods on the object:
class Entry
attr_reader :loc, :action, :changefreq, :priority, :lastmod
end
Next you need to decide how this object will be initialized. It seems like you will need both the city and #country_host for this:
class Entry
attr_reader :loc, :action, :changefreq, :priority, :last mod
def initialize(city, country_host_value)
#loc = ActionController::Integration::Session.new.url_for(:controller => 'cities', :action => 'show', :city_name => city.name, :host => country_host_value)
#changefreq = 0.8 # might actually want to just make this a constant
#priority = 'monthly' # another constant here???
#lastmod = city.updated_at
end
end
Finally add your XML builder method to the class:
class Entry
attr_reader :loc, :action, :changefreq, :priority, :last mod
def initialize(city, country_host_value)
#loc = ActionController::Integration::Session.new.url_for(:controller => 'cities', :action => 'show', :city_name => city.name, :host => country_host_value)
#changefreq = 0.8 # might actually want to just make this a constant
#priority = 'monthly' # another constant here???
#lastmod = city.updated_at
end
def write_entry_to_xml(xml_document)
url = Nokogiri::XML::Node.new( "url" , xml_document )
%w{loc changefreq priority lastmod}.each do |node|
url << Nokogiri::XML::Node.new( node, xml_document ).tap do |n|
n.content = send(node)
end
end
url.to_xml
end
end
Now that your hash has been refactored, you can update your other class(es) to use the new object:
class WhateverClassThisIs
def entry(city)
Entry.new(city, #country_host.value)
end
end
It's not clear how the XML writer method is being called, but you would need to update that as well to use the new write_entry_to_xml method, passing in the xml document as an argument.

Related

Save array of data from one check_box_tag

I have view that created from сontributed API
=form_tag add_group_vk_vk_entries_path, method: :put do
-length_of_array = #vk_groups['message']['vk'].length
.row-fluid
-#vk_groups['message']['vk'][1..length_of_array].each do|item|
.span4
p= check_box_tag "vk_groups[]", item['gid']
p=item['name']
p=image_tag item['photo'], :size => "100x100",:class => "img-circle"
= submit_tag "ok"
I want to sent the data from this api to my controller by check_box_tag. I want to send not only item['gid'] i want to sent to my controller all data that i checked through one check_box_tag but i don't anderstand how.
In my controller
def add_group_vk
params[:vk_groups].each do |item|
if VkEntry.not_exists?(item) == true
VkEntry.create!(
:git => item
)
end
end
redirect_to vk_entries_url
end
i want something like this
def add_group_vk
params[:vk_groups].each do |item|
if VkEntry.not_exists?(item) == true
VkEntry.create!(
:git => item[:gid],
:name=> item[:name],
:ser=> item[:ser],
:photo=> item[:photo]
)
end
end
redirect_to vk_entries_url
end
First, I'm assuming that your above generates the check boxes with names like:
vk_groups[100], vk_groups[101],...
All you can really extract is a list of id's, they're in the the hash key, the value is not important.
params[:vk_groups] will yield a hash, iterate over the hash like so
def add_group_vk
params[:vk_groups].each do |key,val|
if VkEntry.not_exists?(key) == true
VkEntry.create!(
:git => key,
:name=> item[:name],
:ser=> item[:ser],
:photo=> item[:photo]
)
end
end
redirect_to vk_entries_url
end
As a result i done:
def add_group_vk
params[:vk_groups].each do |key,val|
item = eval val
if VkEntry.not_exists?(key) == true
VkEntry.create!(
:gid => key,
:name => item['name'],
:screen_name => item['screen_name'],
:is_closed => item['is_closed'],
:is_admin => item['is_admin'],
:is_member => item['is_member'],
:type_vk => item['type_vk'],
:photo => item['photo'],
:photo_medium => item['photo_medium'],
:photo_big => item['photo_big']
)
end
end
redirect_to vk_entries_url
end
In view
p= check_box_tag "vk_groups[#{item['gid']}]", item

Active Record and file: How do i write Json file with my data?

How do I write a data in table event to json file?
Please see this code:
In model event.rb
class Event < ActiveRecord::Base
attr_accessible :name, :event_description, :start_at, :end_at, :status, :eventable_id
has_event_calendar
belongs_to :eventable, polymorphic: true
after_save :write_json
end
def write_json
Event.all.each do |event|
#eventJson = {
"id" => event.id,
"start" => event.start_at,
"end" => event.end_at,
"title" => event.name,
"body" => event.event_description,
"status" => event.status
}
end
File.open("public/event.json","w") do |f|
f.write(#eventJson.to_json)
end
end
In file Json there's one record, but in table event there are many records. How do I write all records from table event to event.json file after saving the record?
public/event.json
{"id":35,"start":"2013-03-28T00:00:00Z","end":"2013-03-28T00:00:00Z","title":"1345edrewrewr","body":"123124","status":"Confirm"}
The problem is that you assign a value to #eventJson in a loop so the previous values are lost. You should use an array:
def write_json
events_json = []
Event.all.each do |event|
event_json = {
"id" => event.id,
"start" => event.start_at,
"end" => event.end_at,
"title" => event.name,
"body" => event.event_description,
"status" => event.status
}
events_json << event_json
end
File.open("public/event.json","w") do |f|
f.write(events_json.to_json)
end
end
In this case, you might want to use map instead of each -- it's much cleaner.
Given that you said the method is in the model, this is how it would look.
class Event < ActiveRecord::Base
...
def self.write_json
record_json = self.all.map{ |record| { self.name => record.attributes } }.to_json
File.open("#{Rails.root}/#{(self.name.underscore)}.json", "w") do |f|
f.write record_json
end
end
end
You could do it in the way below:
def write_json
File.open('public/event.json', 'w') { |f| f.write(Event.all.to_json) }
end
If you want to save specific fields, you can do it in this way:
def write_json
File.open('public/event.json', 'w') do |f|
f.write(Event.select(:id, :start, :end, :title, :body, :status).to_json)
end
end

Ruby on Rails - right way to take form input and insert it into the database

I have this form:
= form_for([:mobile,#disclosure], :html => {:id => "disclosure-form", :remote => true}) do |f|
%p
=f.label :display_as, (t :select_disclosure_type)
=f.select :display_as, options_from_collection_for_select(Disclosure.basics, :display_as,
:name, f.object.display_as)
%p
=f.label :notes, (t :notes)
=f.text_area :notes, :class => "#{validation_rules(:free_disclosure_notes)}", :rows => 5 , :id => "disclosure_notes_entry"
= buttonset({:submit_label => (t "buttons.influencers.disclosures.create"),:submit_css_class => "call-to-action",
:cancel_url => "#",:direction => :left_to_right})
and I have this controller so far:
def create
Rails.logger.debug "-"*100
Rails.logger.debug session.inspect
Rails.logger.debug "-"*100
provider = nil
#disclosure = params[:disclosure-form].blank?
resource = build_resource({})
begin
if disclosure.nil?
print "hello 1"
else
print "hello 2"
end
rescue Exception => ex
Rails.logger.debug ex
end
respond_to do |format|
format.html{}
end
end
But I am not sure how to get the #disclosures object to be populated so that I can insert it into the database?
How do I get the right data out of the form and add it to the database?
Thanks!!
Your form data should be in params[:disclosure] hash. So, in your create action you would do something like:
def create
#disclosure = Disclosure.new(params[:disclosure])
if #disclosure.save
# redirect to show or something else
else
# render 'new' for with validation errors
end
end
This should save your object in DB. If there is no validation errors.
I'm not sure what this line does: #disclosure = params[:disclosure-form].blank?

In Rails 3.1, how can I create an HTML table generator that uses block style formatting

I'm developing an application that displays tabular data in many different areas and I find myself constantly using the same HTML table structure over and over. For example a particular table looks like this:
%table.zebra-striped#user-table{ :cellspacing => "0" }
%colgroup
%col{:id => "email"}
%col{:id => "username"}
%col{:id => "sign-in-count"}
%col{:id => "last-sign-in-at"}
%thead
%tr
%th{:id => "email-head", :scope => "col"} E-mail
%th{:id => "username-head", :scope => "col"} Username
%th{:id => "sign-in-count-head", :scope => "col"} Sign Ins
%th{:id => "last-sign-in-at-head", :scope => "col"} Last Sign In
%tbody
- #users.each do |user|
%tr{ :class => zebra }
%td
=h user.email
%td
=h user.username
%td
=h user.sign_in_count
%td
=h user.last_sign_in_at
Ideally, I would like to create some kind of helper method where I could do something like:
= custom_table_for #users do
= column :email
= column :username do |user|
= link_to user.username, user_path(user)
= column "Sign Ins", :sign_in_count
= column :last_sign_in_at
This way I can change the formatting of the data in the columns and the column header names if I'm not happy with default values, but have the table generated for me.
I suppose I could create a normal helper, but I'd have to use arrays and I have no idea how I could include custom data formatting per column.
active_admin has something similar to this which you can see here: http://activeadmin.info/docs/3-index-pages/index-as-table.html
Any leads or ideas would be greatly appreciated.
I just came up with this:
A few points:
The line #columns = [] is a reset so you can call it more than once.
The yield in the custom_table_for calls the block that you pass it.
The block in the column method is stored and called in custom_table_for if it is set.
I included a sample class to show the usage too.
please note I did this outside of a rails app and you almost certainly want to use http://api.rubyonrails.org/classes/ActionView/Helpers/TagHelper.html#method-i-content_tag instead of the p "<table>" this is merely for sample purposes when you run it in the console.
module TableHelper
def custom_table_for(items)
#columns = []
yield
p "<table>"
#columns.each do |c|
p "<th>#{c[:value]}</th>"
end
items.each do |e|
p "<tr>"
#columns.each do |c|
e[c[:name]] = c[:block].call(e[c[:name]]) if c[:block]
p "<td>#{e[c[:name]]}</td>"
end
p "</tr>"
end
p "</table>"
end
def column(name, value = nil, &block)
value = name unless value
#columns << {:name => name, :value => value, :block => block}
end
end
class ExampleTable
include TableHelper
def test
#users = [{:email => "Email 1", :username => "Test User"}, {:email => "Email 2", :username => "Test User 2"}]
custom_table_for #users do
column :email, "Email"
column :username do |user|
user.upcase
end
end
end
end
et = ExampleTable.new
et.test
UPDATE
I migrated this to rails to use content_tags
module TableHelper
def custom_table_for(items)
#columns = []
yield
content_tag :table do
thead + tbody(items)
end
end
def thead
content_tag :thead do
content_tag :tr do
#columns.each do |c|
concat(content_tag(:th, c[:value]))
end
end
end
end
def tbody(items)
content_tag :tbody do
items.each { |e|
concat(content_tag(:tr){
#columns.each { |c|
e[c[:name]] = c[:block].call(e[c[:name]]) if c[:block]
concat(content_tag(:td, e[c[:name]]))
}
})
}
end
end
def column(name, value = nil, &block)
value = name unless value
#columns << {:name => name, :value => value, :block => block}
end
end
To compliment #gazler's response, here's a way to make a table of a single resource-- column one for attribute names, column two for their values:
module TableHelper
#resource = nil
def simple_table_for(resource)
#resource = resource
content_tag :table do
content_tag :tbody do
yield
end
end
end
def row(key, label = nil, &block)
if key.is_a? String
label = key
end
content_tag(:tr) {
concat content_tag :td, label || key.capitalize
concat content_tag(:td ){
if block_given?
yield
else
#resource.send(key)
end
}
}
end
end

Where to put constants in Rails

I have a few constants which are arrays that I don't want to create databse records for but I don't know where to store the constants without getting errors.
For example
CONTAINER_SIZES = [["20 foot"],["40 foot"]]
Where can I store this so all models and controller have access to this?
I will write my way to you.
class User < ActiveRecord::Base
STATES = {
:active => {:id => 100, :name => "active", :label => "Active User"},
:passive => {:id => 110, :name => "passive", :label => "Passive User"},
:deleted => {:id => 120, :name => "deleted", :label => "Deleted User"}
}
# and methods for calling states of user
def self.find_state(value)
if value.class == Fixnum
Post::STATES.collect { |key, state|
return state if state.inspect.index(value.to_s)
}
elsif value.class == Symbol
Post::STATES[value]
end
end
end
so i can call it like
User.find_state(:active)[:id]
or
User.find_state(#user.state_id)[:label]
Also if i want to load all states to a select box and if i don't want some states in it (like deleted state)
def self.states(arg = nil)
states = Post::STATES
states.delete(:deleted)
states.collect { |key, state|
if arg.nil?
state
else
state[arg]
end
}
end
And i can use it now like
select_tag 'state_id', User.states.collect { |s| [s[:label], s[:id]] }
I put them directly in the model class.
class User < ActiveRecord::Base
USER_STATUS_ACTIVE = "ACT"
USER_TYPES = ["MANAGER","DEVELOPER"]
end

Resources