Time format in ActiveAdmin - ruby-on-rails

I have no idea how i can format time in ActiveAdmin.
This is my index list:
index do
selectable_column
column :book
column :user
column :time
actions
end
How can i format field :time as %H:%i:%s? Is it possible.
I need something like:
:format => :short

In config/initializers/active_admin.rb, look for localize_format:
config.localize_format = '%H:%i:%s'

If you want to change it every where then modify the format in config/locale/en.yml like so
en:
time:
formats:
long: "%Y-%m-%d %H:%M:%S"
else for just your present column then do
column(:time) { |time| object.time.strftime( "%Y-%m-%d %H:%M:%S") }

The Good way: Use a decorator.
The Poor way: column (:time) {|obj| obj.time.to_s(:short)}
With a decorator (create a decorators directory)
app/decorators/results_decorator.rb
class ResultsDecorator
def intialize(result)
#result = result
end
def time
unless #result.time.nil?
#result.time.to_s(:short)
end
end
end
app/admin/result.rb
index do
selectable_column
column :book
column :user
column ('Time') {|result| ResultsDecorator.new(result).time }
actions
end

Related

How can we assign values to certain model variables in ruby on rails forms without the user having to input them?

I have generated a scaffold in rails to generate a model called transactions which has :
from(int)
to(int)
amount(double)
status(string)
kind(string)
start(datetime)
effective(datetime).
A form to this effect was automatically created. What I want to know is, is there a way to only get some of these values from the user, and add the others automatically? In this case, from, to, amount and kind need to be entered by the user. status should always be defaulted to "pending", and start should have the current date and time. effective should be null.
You can do this in many ways
First:
You can use Active Record Callbacks to accomplish this.
Add callback in your model app/models/transaction.rb
before_create :assign_default_attributes
def assign_default_attributes
self.status = 'pending' if self.pending.blank?
self.start = Time.now if self.start.blank?
end
Note: Make sure you remove status, start and effective from permitted params from controller.
Second
Modify app/controllers/transactions_controller.rb create action.
def create
transaction = Transaction.new(status: 'pending', start: Time.now)
transaction.assign_attributes(transaction_params)
if transaction.save
redirect_to transactions_path, notice: 'Transaction Created'
else
flash[:alert] = 'Enter Valid data'
render :new
end
end
Note: Make sure you remove status, start and effective from permitted params from controller.
You can add a migration to change the default values:
class ChangeDefaultValueForStatus < ActiveRecord::Migration
def change
change_column :transactions, :status, :string, default: "Pending"
change_column :transactions, :effective, :datetime, default: nil
end
end
Instead of using start, you can use the in-built timestamps to automatically get the date and time of when a record was created or updated:
class AddTimestampsToTransactions < ActiveRecord::Migration
def change_table
add_column(:transactions, :created_at, :datetime)
add_column(:transactions, :updated_at, :datetime)
end
end
i think you need default values
for status,set the default value.
Add this in your migration to add default value to columns-
t.string :status, default: "Pending"
check Migration api for more details
For start date,you can set todays time in your form.
<div class="form_group">
<label>Start time:</label></br>
<%= f.datetime_select :starts_at , :class=>"form-control",:start_year => Date.current.year, :end_year => Date.current.year,:selected=> Date.today, :order=> [:day, :month, :year],:start_year=> Time.now.year,:default=> 1.days.from_now,:prompt=> {day: 'Choose day', month: 'Choose month', year: 'Choose year'},:placeholder=>"Enter start time",:required=>true %>
</div>
Check the datetime_select api for more details.

2 fields, 1 model attribute, date not parsing

I have 2 fields that is asscociated with 1 attribute in my model. I am applying it in 2 of my attributes: start_at, and end_at. I am using Timepicker Plugin for jQuery.
I based my answer here: https://stackoverflow.com/questions/18461798/rails-4-convert-datetime-into-separate-date-and-time-fields#=
MY PROBLEM IS THAT THE DATE IS NOT PARSING PROPERLY.
Below are my codes:
Appointment model:
before_save :convert_to_datetime
attr_accessor :start_date, :start_time, :end_date, :end_time
def start_date
start_at.strftime("%d/%m/%Y") if start_at.present?
end
def start_time
start_at.strftime("%I:%M%p") if start_at.present?
end
def start_date=(date)
# Change back to datetime friendly format
#start_date = Date.parse(date).strftime("%Y-%m-%d")
end
def start_time=(time)
# Change back to datetime friendly format
#start_time = Time.parse(time).strftime("%H:%M:%S")
end
def end_date
end_at.strftime("%d/%m/%Y") if end_at.present?
end
def end_time
end_at.strftime("%I:%M%p") if end_at.present?
end
def end_date=(date)
# Change back to datetime friendly format
#end_date = Date.parse(date).strftime("%Y-%m-%d")
end
def end_time=(time)
# Change back to datetime friendly format
#end_time = Time.parse(time).strftime("%H:%M:%S")
end
def convert_to_datetime
self.start_at = DateTime.parse("#{#start_date} #{#start_time}")
self.end_at = DateTime.parse("#{#end_date} #{#end_time}")
end
Strong params:
params.require(:task).permit(:category_id, :subcategory_id, :title, :description, :pay_offer, :pay_type, :county_id, :area_id, appointments_attributes: [:id, :start_date, :start_time, :end_date, :end_time])
If you are wondering, appointment is a nested attribute of task model.
Here is the error:
ArgumentError (invalid date):
app/models/appointment.rb:26:in `parse'
app/models/appointment.rb:26:in `start_date='
app/controllers/tasks_controller.rb:9:in `create'
Its referring to this line: #start_date = Date.parse(date).strftime("%Y-%m-%d")
LOG:
"appointments_attributes"=>{"0"=>{"start_date"=>"3/20/2015",
"start_time"=>"12:30 AM",
"end_date"=>"3/21/2015",
"end_time"=>"01:30 AM"}}},
"commit"=>"Create Task"}
Please help. :(
The problem is that Ruby is expecting date in %d/%m/%Y format, and you are passing it in %m/%d/%Y (notice that day and month have changed place). Date "3/20/2015" is invalid because there is no 20th month. :)
Instead of using just Date.parse you should use strptime which allows you to specify date format that you want to parse.
Date.strptime(date, "%m/%d/%Y")

ruby/rails how to ignore a comma in when ordering

I have a price field for a product in a catalog. Sometimes the admin user is putting a comma when dealing with thousands (ex: $10,000) and sometimes he is just doing $6000. While I would like to simply tell him to do it one way or the other, I would also like to solve the issue programmatically.
The #show action responsible is here:
def show
#category = Category.find_by_url_name(params[:category_id])
#brand = Brand.find(params[:id])
#search = Product.find(:all, :conditions => ['brand_id = ? and category_id = ?', #brand.id, #category.id],
:order=> params[:order] || 'price DESC')
#products = #search.paginate(:page => params[:page], :per_page => 12 )
#meta_title = "#{#brand.name}"
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #brand }
end
end
I also have a sort_options helper in my application helper that is providing the ordering options to the site user:
def product_sort_options
options_for_select([
['', nil],
['Newest to Oldest', 'descend_by_date'],
['Oldest to Newest', 'ascend_by_date'],
['Price: Highest to Lowest', 'descend_by_price'],
['Price: Lowest to Highest', 'ascend_by_price'],
['Name', 'ascend_by_name']
])
end
any ideas?
To make it a full answer - price should not be a string. The fact that you have 300 products now is not a big deal.
Make a migration:
rails generate migration decimalise
Then edit it (db/migrate/*decimalise.rb), and write something like this:
class Decimalise < ActiveRecord::Migration
def up
connection = ActiveRecord::Base.connection()
# kill the weird chars in the string field
connection.execute("UPDATE products SET price = REPLACE(REPLACE(price, ',', ''), '$', '')")
# convert the string column into a decimal one
change_table :products do |t|
# adjust for your use case - this gives you values up to 9999999.99
# if you need more, increase the 10
t.column :price, :decimal, :precision => 10, :scale => 2
end
end
def down
change_table :products do |t|
t.column :price, :string, :limit => 10
end
end
end
then finally, run
rake db:migrate
(untested, you will probably need to tweak. also, back up your DB before any tinkering - I'll not be responsible for any data loss you suffer)
EDIT One thing I forgot: how to print it out.
<%= number_to_currency #product.price %>
should give you something like $1,999.99 for a price of 1999.99.
You can use String.gsub to search the commas and replace them by nothing.

Rails Way: Formatting Value Before Setting it in the Model?

I have form fields where the user enters in:
percents: 50.5%
money: $144.99
dates: Wednesday, Jan 12th, 2010
...
The percent and money type attributes are saved as decimal fields with ActiveRecord, and the dates are datetime or date fields.
It's easy to convert between formats in javascript, and you could theoretically convert them to the activerecord acceptable format onsubmit, but that's not a decent solution.
I would like to do something override the accessors in ActiveRecord so when they are set it converts them from any string to the appropriate format, but that's not the best either.
What I don't want is to have to run them through a separate processor object, which would require something like this in a controller:
def create
# params == {:product => {:price => "$144.99", :date => "Wednesday, Jan 12, 2011", :percent => "12.9%"}}
formatted_params = Product.format_params(params[:product])
# format_params == {:product => {:price => 144.99, :date => Wed, 12 Jan 2011, :percent => 12.90}}
#product = Product.new(format_params)
#product.save
# ...
end
I would like for it to be completely transparent. Where is the hook in ActiveRecord so I can do this the Rails Way?
Update
I am just doing this for now: https://gist.github.com/727494
class Product < ActiveRecord::Base
format :price, :except => /\$/
end
product = Product.new(:price => "$199.99")
product.price #=> #<BigDecimal:10b001ef8,'0.19999E3',18(18)>
You could override the setter or getter.
Overriding the setter:
class Product < ActiveRecord::Base
def price=(price)
self[:price] = price.to_s.gsub(/[^0-9\.]/, '')
end
end
Overriding the getter:
class Product < ActiveRecord::Base
def price
self[:price].to_s.gsub(/[^0-9\.]/, ''))
end
end
The difference is that the latter method still stores anything the user entered, but retrieves it formatted, while the first one, stores the formatted version.
These methods will be used when you call Product.new(...) or update_attributes, etc...
You can use a before validation hook to normalize out your params such as before_validation
class Product < ActiveRecord::Base
before_validation :format_params
.....
def format_params
self.price = price.gsub(/[^0-9\.]/, "")
....
end
Use monetize gem for parsing numbers.
Example
Monetize.parse(val).amount

Globalize2 and migrations

I have used globalize2 to add i18n to an old site. There is already a lot of content in spanish, however it isn't stored in globalize2 tables. Is there a way to convert this content to globalize2 with a migration in rails?
The problem is I can't access the stored content:
>> Panel.first
=> #<Panel id: 1, name: "RT", description: "asd", proje....
>> Panel.first.name
=> nil
>> I18n.locale = nil
=> nil
>> Panel.first.name
=> nil
Any ideas?
I'm sure you solved this one way or another but here goes. You should be able to use the read_attribute method to dig out what you're looking for.
I just used the following to migrate content from the main table into a globalize2 translations table.
Add the appropriate translates line to your model.
Place the following in config/initializers/globalize2_data_migration.rb:
require 'globalize'
module Globalize
module ActiveRecord
module Migration
def move_data_to_translation_table
klass = self.class_name.constantize
return unless klass.count > 0
translated_attribute_columns = klass.first.translated_attributes.keys
klass.all.each do |p|
attribs = {}
translated_attribute_columns.each { |c| attribs[c] = p.read_attribute(c) }
p.update_attributes(attribs)
end
end
def move_data_to_model_table
# Find all of the translated attributes for all records in the model.
klass = self.class_name.constantize
return unless klass.count > 0
all_translated_attributes = klass.all.collect{|m| m.attributes}
all_translated_attributes.each do |translated_record|
# Create a hash containing the translated column names and their values.
translated_attribute_names.inject(fields_to_update={}) do |f, name|
f.update({name.to_sym => translated_record[name.to_s]})
end
# Now, update the actual model's record with the hash.
klass.update_all(fields_to_update, {:id => translated_record['id']})
end
end
end
end
end
Created a migration with the following:
class TranslateAndMigratePages < ActiveRecord::Migration
def self.up
Page.create_translation_table!({
:title => :string,
:custom_title => :string,
:meta_keywords => :string,
:meta_description => :text,
:browser_title => :string
})
say_with_time('Migrating Page data to translation tables') do
Page.move_data_to_translation_table
end
end
def self.down
say_with_time('Moving Page translated values into main table') do
Page.move_data_to_model_table
end
Page.drop_translation_table!
end
end
Borrows heavily from Globalize 3 and refinerycms.

Resources