rails simple form date input - separate integer inputs - ruby-on-rails

I have a date column in my schema called dob.
I'm using a simple form to render the dob.
I want to format the input as 3 separate integer inputs.
The closest i have gotten is this code:
<%= f.input :dob, order: [:day, :month, :year] %>
However it produces this:
which is close. However i need the inputs to be integer inputs, and not dropdowns. Also i would like the month the be an integer as well.
If i use as: :integer, it just returns one single input.
Any ideas? The simple form documentation is not particularly helpful.
Thanks

you will need 3 integer inputs:
f.integer :day
f.integer :month
f.integer :year
This requires you to have day, month, and year attribute accessors on your model, and to assemble the date from the component integers, perhaps in the controller, e.g.
# users_controller.rb
def create
params[:dob] = Date.new(params[:year], params[:month], params[:day])
#... the rest of the method
end
in order to populate the integer fields for editing, you'll need methods on your model, e.g.
# in User.rb
def day
dob.day
end
# ...etc
You will also need to check that the data that the user inputs is within range.
All this special handling is why this is not normally done.

Related

Active Scaffold: field search on column with timestamp

I enabled field search functionality in my controller according the FieldSearch-API-Documentation.
I have enabled field search on two columns as below
class FooController < ApplicationController
active_scaffold 'foo' do |config|
# allowed actions
config.actions = [:create, :update, :delete, :field_search, :list, :nested, :show]
# columns
config.columns = [:date, :created_at]
# searchable columns
config.field_search.columns = :date, :created_at
config.list.always_show_search = true
# list columns
config.list.columns = [:date, :created_at]
[...]
end
end
The column date is of type date and the column created_at is of type timestamp within the postgresql database.
With the configuration parameters above I get successfully a search form on the view rendered by active scaffold. On the search form there is an dropdown with operators (e.g. BETWEEN) and two input controls for selecting the range.
The Problem now is, that searching by date works fine and searching by created_at doesn't work.
After an exhaustive research I found a hint which describes that active scaffold uses by default the datetime format which is configured under ./config/locales/en.yml and shows in my case like this.
en:
time:
formats:
default: "%Y%m%d%H%M%S"
Obviously it does matter how the input format is. The search input for searching by created_at is e.g: from 20180101000000 to 20181231000000.
On the Column-API-Documentation I found the following:
options[:format] can be set for:
date and time columns, and it will be used as the format argument of I18n.localize to format them.
I not understand what kind of value I have to define in the option parameter within the controller?
config.columns[:created_at].options[:format] = ???
Just found the answer while writing the question :-)
If I define in ./config/locales/en.yml a new entry e.g. timestamp as below
en:
time:
formats:
timestamp: "%Y%m%d%H%M"
and do in my controller the following
config.columns[:created_at].options[:format] = "timestamp"
then I am successfully able to search by created_at with the input 201801010000 and 201812310000.

Date filter not displaying

I created a new datetime row for a page, it works well. The column displays all the specific dates, but when I want to show specific rows using a date filter, it doesn't display a thing.
In the model:
before_validation :payment_date
def payment_date
self.payment_date = sales_order.payment_transactions.last.date
end
The date filter from the controller file:
filter :payment_date, :as => :date_range, :collection => proc { Complaint.all.map{|c| c.sales_order.try(:payment_transactions).try(:last).try(:date)} }
I suppose I did a couple of mistakes and i'm curious where the bad coding is.
In AA filtering is based on Ransack, so your filter would look as follows (assuming sales_order is an association on your model):
filter :sales_order_payment_transactions_date, label: 'Some label', as: :date_range
Here you basically go along the association chain - it is acceptable with ransack.

Rails - How should mulitple checkboxes be combined as one value in a database?

As part of an application I'm building, I need to store the days on which some action needs to happen.
Currently I have this stored in a 7-digit bit-string, with each digit corresponding to one day of the week. A value of 1 for any day means the action should happen that day, a value of 0 means it should not.
Ex. String 0101110 means the action should run on Tuesday, Thursday, Friday and Saturday every week.
In my form, I have seven checkboxes set up, one for each name.
How would I go about merging these seven Boolean results into the one bitstring, such that I can save it in the database?
Would you do this in the view, or the model?
I've done some thinking myself, and one option (in the view) could be to set up a hidden field in the form that is the result of joining/concatenating the seven Booleans from the checkboxes. Then the checkboxes' values could be discarded on submit. I'm just not quite sure how to do this in rails.
Another option could be to handle the merging in the model. Again - not quite sure what to do.
Any help appreciated, thanks in advance.
Define the checkbox values for the weekdays as virtual attributes on your model, and concatenate them on a before_save hook. In your model:
attr_writer :mon, :tue, :wed, :thu, :fri, :sat, :sun
before_save :set_weekdays
private
def set_weekdays
self.weekdays = bitstr(#mon) + bitstr(#tue) + bitstr(#wed) # etc
end
def bitstr(bool)
bool ? "1" : "0"
end
Make sure to permit mon and co as strong parameters for the model in Rails 4. You might also want to define getters for these attributes that would get filled from the bitstring, so that the form could render with the correct checkboxes pre-selected on edits.
I am assuming the week column is week
You can make the week column of type: text and add this to your model
serialize :week : this helps to save an array in the column
next, create a class Week, where week.rb:
class Week
include ActiveModel::Model
attr_accessor :id, :name
DAYS = [
{id: 1, "day" => "monday"},
{id: 2, "day" => "tuesday"},
...
]
def self.days
DAYS.map {|d| self.new(
id: d[:id],
name: d[:day]
)}
end
end
and then, you can call the checkboxes from the view as follow:
<%= f.collection_check_boxes(:week, Week.days, :id, :name, include_hidden: false) do |b| %>
<%= b.check_box(class: "check_box") %> <%= b.object.name %>
<% end %>
lastly, dont forget to make the week atribute accesible from the controller. In rails 4, this will be:
params.require(:user).permit(week: [])
Hope this helps you?

Select menu for type field and map integers to text in rails

[I'm new to rails, and I hope it's not a silly question, seen a similar question but it's for PHP and doesn't help in my case]
To explain my problem, I'm using a analogy to users here. Lets say I have users table in my app, I have added a field called user_type to users table. Now I want to specify which type of user is.
lets say I have 5 types of users eg. moderator, administrator, consumer etc.
I don't want to make user_type field to be string type to store user type. Instead I want to make user_type to store integer and then map these integer values to respective string values.
Advantage to this approach is that I can change what a user type is called. Suppose that I no longer wish to call consumer a consumer and instead wish to call it something else.
I believe storing integer in db is better and gives some flexibility.
I know I can create select menu using formtastic(I'm using active_admin as admin panel, formtastic is used for forms)
<%= f.input :user_type, :as => :select, :collection => {
0 => "Admin",
1 => "Moderator",
2 => "Consumer",
} %>
and then store values in db, and then select these users from db.
I want to know Is there a better way or approach to do it in rails or there is some gem available to do this or some other approach you prefer and why you recommend it.
I'm using postgresql as database.
Thanks!!
I personally like the active_enum gem combined to simple_form because it's really simple to implement and they work fine together.
In your case, you would have to define an enum class like this :
class Type < ActiveEnum::Base
value 1 => 'Admin'
value 2 => 'Moderator'
value 3 => 'Consumer'
end
Then in your User model, you simply add this :
enumerate :user_type, :with => Type
And what is really great with simple_form is that you simply have to call :
<%= f.input :user_type =>
to get a select with all your values.
Try this
# user.rb
USER_TYPES = { moderator: 1, superuser: 2, admin: 3, client: 4 }
# views
select :user, :user_type, User::USER_TYPES
This saves the integer values to the database. If you want to get the the string equivalent, use User::USER_TYPES.key(#user.user_type)
EDIT: forgot to add scopes
scope :moderators, where(user_type: USER_TYPES[:moderator])
scope :superusers, where(user_type: USER_TYPES[:superuser])
...
or
USER_TYPES.each do |user_type, value|
scope :"#{user_type}s", where(user_type: USER_TYPES[user_type])
end

mongoid batch update

I'd like to update a massive set of document on an hourly basis.
Here's the
fairly simple Model:
class Article
include Mongoid::Document
field :article_nr, :type => Integer
field :vendor_nr, :type => Integer
field :description, :type => String
field :ean
field :stock
field :ordered
field :eta
so every hour i get a fresh stock list, where :stock,:ordered and :eta "might" have changed
and i need to update them all.
Edit:
the stocklist contains just
:article_nr, :stock, :ordered, :eta
wich i parse to a hash
In SQL i would have taken the route to foreign keying the article_nr to a "stock" table, dropping the whole stock table, and running a "collection.insert" or something alike
But that approach seems not to work with mongoid.
Any hints? i can't get my head around collection.update
and changing the foreign key on belongs_to and has_one seems not to work
(tried it, but then Article.first.stock was nil)
But there has to be a faster way than iterating over the stocklist array of hashes and doing
something like
Article.where( :article_nr => stocklist['article_nr']).update( stock: stocklist['stock'], eta: stocklist['eta'],orderd: stocklist['ordered'])
UPDATING
You can atomically update multiple documents in the database via a criteria using Criteria#update_all. This will perform an atomic $set on all the attributes passed to the method.
# Update all people with last name Oldman with new first name.
Person.where(last_name: "Oldman").update_all(
first_name: "Pappa Gary"
)
Now I can understood a bit more. You can try to do something like that, assuming that your article nr is uniq.
class Article
include Mongoid::Document
field :article_nr
field :name
key :article_nr
has_many :stocks
end
class Stock
include Mongoid::Document
field :article_id
field :eta
field :ordered
belongs_to :article
end
Then you when you create stock:
Stock.create(:article_id => "123", :eta => "200")
Then it will automaticly get assign to article with article_nr => "123"
So you can always call last stock.
my_article.stocks.last
If you want to more precise you add field :article_nr in Stock, and then :after_save make new_stock.article_id = new_stock.article_nr
This way you don't have to do any updates, just create new stocks and they always will be put to correct Article on insert and you be able to get latest one.
If you can extract just the stock information into a separate collection (perhaps with a has_one relationship in your Article), then you can use mongoimport with the --upsertFields option, using article_nr as your upsertField. See http://www.mongodb.org/display/DOCS/Import+Export+Tools.

Resources