I have two models, being an Employee and a WorkingPattern. An instance of an Employee belongs_to an Working Pattern.
The Working Pattern looks like this
:id => :integer,
:name => :string,
:mon => :boolean,
:tue => :boolean,
:wed => :boolean,
:thu => :boolean,
:fri => :boolean,
:sat => :boolean,
:sun => :boolean
I need to know if an Employee should be at work today. So, if today is a Tuesday and that employee's working pattern record reports that :tue = true then return true, etc. I don't have the option of renaming the fields on the WorkingPattern model to match the days names.
I know that
Time.now.strftime("%A")
will return the name of the day. Then I figured out I can get the first 3 characters of the string by doing
Time.now.strftime("%A")[0,3]
so now I have "Tue" returned as a string. Add in a downcase
Time.now.strftime("%A")[0,3].downcase
and now I have "tue", which matches the symbol for :tue on the WorkingPattern.
Now I need a way of checking the string against the correct day, ideally in a manner that doesn't mean 7 queries against the database for each employee!
Can anyone advise?
You can use %a for the abbreviated weekday name. And use send to dynamically invoke a method
employee.working_pattern.send(Time.now.strftime("%a").downcase)
Use send to invoke a method, stored in a variable, on an object.
Both of these are identical:
user.tue # true
user.send('tue') # true
You can access an attibute using [], just like a Hash. No need to use send or even attributes.
day = Time.now.strftime("%a").downcase
employee.working_pattern[day]
Butchering strings makes me feel a little uneasy
Construct a hash of day numbers:
{0 => :sun
1 => :mon,
2 => :tue,
...}
Then use Time.now.wday (or Time.zone.now.wday if you want to be timezone aware) to select the appropriate value from the hash
You can then use that string on employee.working_pattern in any of the ways described by the other answers:
employee.working_pattern.send(day_name)
employee.working_pattern.read_attribute[day_name]
enployee.working_pattern[day_name]
Related
I have an Activity_Part model with a field called activity_json. this field is a hash that has a key named "image". I want to query/select only the ID of all Activity_Part only with activity_json field with key "image"
ActivityPart < ApplicationRecord {
:id => :integer,
:owner_id => :integer,
:activity_type => :string,
:activity_json => :json,
I thought of doing something like this:
x = ActivityPart.all
x.pluck(activity_json: 'image')
but I don't know how to return just the Activity ID with all the images in the activty_json field
I'll assume that you're using postgres.
jsonb type has the ? operator which can be used like this: ActivityPart.where("activity_json ? 'image'") as per documentation.
If your column is of a json type then consider changing it to jsonb. You can alternatively cast it to jsonb in the query like so: ActivityPart.where("activity_json::jsonb ? 'image'") but be aware that this might negatively affect the performance of the query.
Friends,
I have a simple query like this one:
ContactForm.where(:is_active => true).order(:name => :asc)
But I want one of my records to appear always first, so I prefixed it with a couple hyphens "--", however, the order clause is not swapping that record to the first place, in fact it's still in the middle, as it wouldn't have those hyphens.
What can be happening?
Thank you.
I suggest you to create another column instead of using that approach. You can use a column named priority with 0 as default.
add_column :contact_form, :priority, :integer, default: 0
Then, you can use this code (assuming that you have flagged the priority record with 1 ):
ContactForm.where(:is_active => true).order(:priority, :name => :asc)
I have a column car_details with 2000 entries, each of which is a hash of info that looks like this:
{"capacity"=>"0",
"wheels"=>"6",
"weight"=>"3000",
"engine_type"=>"Diesel",
"horsepower"=>"350",
"fuel_capacity"=>"35",
"fuel_consumption"=>"30"}
Some cars have more details, some have less. I want to rename the "fuel_consumption" key to "mpg" on every car that has that key.
Well, a previous answer will generate 2000 requests, but you can use the REPLACE function instead. Both MySQL and PostgreSQL have that, so it will be like:
Car.update_all("car_details = REPLACE(car_details, 'fuel_consumption', 'mpg')")
Take a look at the update_all method for the conditions.
See also PostgreSQL string functions and MySQL string functions.
Answer posted by #Ivan Shamatov works very well and is particular important to have good performances on huge databases.
I tried it with a PostgreSQL database, on a jsonb column.
To let it works we have to pay same attention to data type casting.
For example on a User model like this:
User < ActiveRecord::Base {
:id => :integer,
:created_at => :datetime,
:updated_at => :datetime,
:email => :string,
:first_name => :string,
:last_name => :string,
:custom_data => :jsonb
}
My goal was to rename a key, inside custom_data jsonb field.
For example custom_data hash content from:
{
"foo" => "bar",
"date" => "1980-07-10"
}
to:
{
"new_foo" => "bar",
"date" => "1980-07-10"
}
For all users records present into my db.
We can execute this query:
old_key = 'foo'
new_key = 'new_foo'
User.update_all("custom_data = REPLACE(custom_data::text, '#{old_key}'::text, '#{new_key}'::text)::jsonb")
This will only replace the target key (old_key), inside our jsonb hash, without changing hash values or other hash keys.
Note ::text and ::jsonb type casting!
As far as I know, there is no easy way to update a serialized column in a data table en masse with raw SQL. The best way I can think of would be to do something like:
Car.find_each do |car|
mpg = car.car_details.delete("fuel_consumption")
car.car_details["mpg"] = mpg if mpg
car.save
end
This is assuming that you are using Active Record and your model is called "Car".
I'm using Ruby on Rails and I'm storing business hours like this:
CREATE TABLE "business_hours" (
"id" integer NOT NULL PRIMARY KEY,
"business_id" integer NOT NULL FOREIGN KEY REFERENCES "businesses",
"day" integer NOT NULL,
"open_time" time,
"close_time" time)
(which came from the thread at:
Storing Business Hours in a Database )
Now I want to pull the hours out for each day of the week and display them, and I'm trying to find the best (or at least a good) way.
Should I just have a helper method that loops through getting the days (from 0..6) for a given business_id and assign it to a variable for the associated day? I feel like there must be a better way -- with an array, or something, but it's hurting my head thinking about it, because I also have a form of 'select's where any of the hours for a given business can be updated at once.
Thanks for any guidance!
Use the enum column plugin to declare the day field as a enum field.
class BusinessHours < ActiveRecord::Migration
def self.up
create_table :business_hours do |t|
t.integer :business_id, :null => false
t.enum :day, :limit =>[:sun, :mon, :tue, :wed, :thu, :fri, :sat], :nill => false
t.time :open_time, :null => false
t.time :close_time, :null => false
end
end
def self.down
drop_table :business_hours
end
end
Now when you do find on the BusinessHour model you will get the day as a string.
b = BusinessHour.find_by_business_id(2).first
p b.day.to_s.camelize #prints Sun/Mon/Tue etc.
You can use the enum_select and enum_radio form helpers to create list box/radio button group for the enum group:
Since the number of days in a week really is fixed, you can join the table 6 times (plus the original) and do a query for a single row. I'd probably just do a single query and loop through the rows though.
Have you considered serializing the business hours? Using serialization you are essentially storing objects in the database.
class BusinessHour < ActiveRecord::Base
serialize :hours
...
end
BusinessHour.create :business => #business, :hours =>
{:mon => [mon_start_time, mon_end_time], :wed => [wed_start_time, wed_end_time],
...}
Personally I would go with the bitwise approach described in linked question. All you really need to do to make it work is write new accessor methods.
It would be easier to find the business and use the associations to retrieve the business_hours rows.
Try this in your view
<% #business.business_hours.each do |hrs| %>
<%= hrs.day_name %>: Open-<%= hrs.open_time %> Close-<%= hrs.close_time %>
<%- end -%>
In your business_hour.rb model file, create a default scope to make sure the days are always listed in order. You can also create the day_name method to make it easier to display the day.
default_scope :order => 'day ASC'
def day_name
case self.day
when 0 then "Sun"
when 1 then "Mon"
...
end
end
How do you check what the datatype is for something that was retrieved from the database?
For example, if I have some instantiation of a model #model with a database field "title", I want to be able to code something like #model.title.type and have it return "String". Does Rails have any built-in functionality for this?
Try this:
#model.column_for_attribute('title').type
Should return :string, :text, :integer, etc.
The ActiveRecord Column class also includes a number of other attributes: default, limit, name, null, precision, primary, scale, sql_type, type.
In Rails 3, for my model "Firm", I'd use Firm.columns_hash.
Firm.columns_hash["name"].type #returns :string
If you want to iterate through them, you'd do something like this:
Firm.columns_hash.each {|k,v| puts "#{k} => #{v.type}"}
which will output the following:
id => integer
name => string
max_trade_qty => integer
and so on.