I'm trying to return the most common text value (country) from the database.
Whilst my first attempt is not producing any errors, I suspect it's not returning the most common value:
#mostpopularroast = Roast.group(:id).order("count(country) DESC").first
Interesting it gives me the exact same result should I use ASC instead.
I'm therefore now trying a solution from this similar question:
#mostpopularroast = Roast.group('country').order('count(*)').limit(1).pluck(:country).first
But this is giving me the error undefined method 'country' for "Country 1":String. Country 1 being the value in the db.
my model
class CreateRoasts < ActiveRecord::Migration[5.1]
def change
create_table :roasts do |t|
t.string :roaster
t.string :name
t.string :country
t.string :region
t.string :bestfor
t.string :beans
t.string :roast
t.string :slug
t.timestamps
end
end
end
You should apply descending ordering to get the most popular country:
Roast.group(:country).select(:country).order("count(*) desc").first.country
Your initial error is not related to this, it is just that you are using pluck, which returns Array object, then you are calling first method on it and getting String object, which is the object that is already the name of the most popular roast country, but then you are trying to call country on it, which results in the exception.
Related
I'm using PostgreSQL with Rails in API mode and I have a row called expired with data type Date and I want to make a trigger that identifies if the expired date is equal to the current date and change my is_expired column from false to true, but I don't know where to start.
I've read a bit of Rails documentation or some libraries like hairtrigger and it seems a bit confusing.
this is my table:
class CreateRifs < ActiveRecord::Migration[7.0]
def change
create_table :rifs do |t|
t.string :name
t.datetime :rif_date
t.string :award_with_sign
t.string :award_no_sign
t.string :plate
t.integer :year
t.float :price
t.integer :numbers
t.integer :with_signs
t.date :expired
t.boolean :is_expired, default: false
t.timestamps
end
end
end
Do you have a specific reason to use a database column for this? Because you could easily write this method on the model:
def expired? # This is actually an override, see next paragraph
expired <= Date.today
end
Or alternatively, if the expired column only gets populated with a past date after it actually has expired (and doesn't, e.g., represent a future expiry), don't write a method at all. Rails automatically provides you with a predicate for every column: a column? method that returns true if column is populated.
You don't need a trigger for this, maybe a scope to only get expired vs not expired records.
class Rif < ApplicationRecord
scope :expired, -> { where('expired < NOW()') }
end
You can then use the scope later on
expired_rifs = Rif.expired
I am having an issue trying to do a bulk reverse geocode using the geocoder rails gem: https://github.com/alexreisner/geocoder
I have the following models:
class School < ActiveRecord::Base
reverse_geocoded_by :latitude, :longitude
has_one :address
end
and
class Address < ActiveRecord::Base
belongs_to :school
end
And the following migrations:
class CreateSchools < ActiveRecord::Migration
def change
create_table :schools do |t|
t.string :name
t.integer :address_id
t.timestamps null: false
end
end
end
and
class CreateAddresses < ActiveRecord::Migration
def change
create_table :addresses do |t|
t.string :line_1
t.string :line_2
t.string :line_3
t.string :city
t.string :region
t.string :country
t.string :code
t.timestamps null: false
end
end
end
and when I run the following line:
rake geocode:all CLASS=School REVERSE=true SLEEP=0.5
I get this error:
ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR: column schools.address does not exist
LINE 1: SELECT "schools".* FROM "schools" WHERE (schools.address IS...
^
: SELECT "schools".* FROM "schools" WHERE (schools.address IS NULL) ORDER BY "schools"."id" ASC LIMIT 1000
I know the readme says this:
"For geocoding your model must provide a method that returns an
address. This can be a single attribute, but it can also be a method
that returns a string assembled from different attributes (eg: city,
state, and country)."
I took that to mean I needed either a method on the School model or the attribute on the school table and I opted for the latter but I'm not sure what I'm missing.
Thanks!
The problem is that the reverse-geocoding rake task starts by loading all the records with no address column yet. It uses this scope:
scope :not_reverse_geocoded, lambda {
where("#{table_name}.#{geocoder_options[:fetched_address]} IS NULL")
}
The problem is you don't have any column on schools you could use. Instead, you should move the reverse_geocoded_by declaration to the Address class. You will also need to either add an addresses.address column or do something like this:
reverse_geocoded_by :latitude, :longitude, fetched_address: :line_1
Also you don't seem to have columns for latitude and longitude. And of course those should be on Address too, not School. After all, if a school can have several addresses, which one is its lonlat?
Sorry about the title, it's really hard to explain but I'll try my best to make it as clear as possible.
So, I have this app that I am building sort of 'Social Shift Trading Network'. So in this app I have a calendar(fullcalendar-rails) that I use, and I generate shifts using a model but I realise that the id generated automatically by the database tend to not be useful when there are a lot of deletion of object or changes because the index is not being reset. So, I thought that I would put a shift_id column in my Shift model and generate id with SecureRandom.urlsafe_base64(8).
But how do I set it as a primary key so that when I edit or call show on it for it to use shift_id as params?
I tried set :id => false, and set :primary => :shift_id but still no result. I believe because my route format is "/shifts/:id/edit(.:format)" formatted to pull :id that it does not work.
Thank for you for any help in advance.
class CreateShifts < ActiveRecord::Migration
def change
create_table :shifts, {:id => false, :primary_key => :shift_id} do |t|
t.string :position
t.datetime :date
t.datetime :start_time
t.datetime :finish_time
t.integer :original_owner
t.integer :current_owner
t.string :shift_id
t.string :shift_posted, :default => "Not Posted"
t.timestamps
end
end
If what I understood is correct, all you want is that the URL becomes something like this
/shifts/:some_random_hash/edit
To do that you don't need to mess your database like that, just generate that normal table, and add that :shift_id field, then tell the model which field to use for the url.
class Shift < ActiveRecord::Base
to_param
shift_id
end
end
This way when you use url_for or shift_path the model will use the :shift_id instead to generate that URL, but internally it would use the auto increment id
Can you teach me how to set an attribute to Array in Model?.
I have tried it but when I use array's method like push, each, I got the error undefined method `push' for nil:NilClass
My migrate look like this:
class CreateContacts < ActiveRecord::Migration
def change
create_table :contacts do |t|
t.string :name
t.string :email
t.string :email_confirmation
t.integer :city_ids, array: true
t.text :description
t.timestamps
end
end
end
I would like to set attribute city_ids to Array.
One important thing to note when interacting with array (or other mutable values) on a model. ActiveRecord does not currently track "destructive", or in place changes. These include array pushing and poping, advance-ing DateTime objects.
Example
john = User.create(:first_name => 'John', :last_name => 'Doe',
:nicknames => ['Jack', 'Johnny'])
john = User.first
john.nicknames += ['Jackie boy']
# or
john.nicknames = john.nicknames.push('Jackie boy')
# Any time an attribute is set via `=`, ActiveRecord tracks the change
john.save
Referrence - link
You need to set a default. Otherwise, the attribute is nil, until you give it a value:
t.integer :city_ids, array: true, default: []
Or, you need to give it a value befor eyou attempt to use it:
c = City.find(...)
c.city_ids ||= []
c.city_ids.push(...)
I am trying to setup a model based on a pre-built model that has the following code in the migration:
def change
create_table :friendships do |t|
t.string :user_id, :friend_user_id
t.string :status
end
end
I get the t.string :status part where a column is being created which will use a string. I don't understand the t.string :user_id, :friend_user_id part where there are two attributes on the same line.
In the first line, two columns are being created named as user_id and friend_user_id having string data type. In the second line there is another column being created named status having string data type. So in migrations you can write all column names in one line which have the same data type. i.e. The migration can be written like this.
def change
create_table :friendships do |t|
t.string :user_id, :friend_user_id, :status
end
end
This is a join table to show relationship. Actually user_id and friend_user_id all refer to id in users table.
Say my id is 10 and yours is 11. I regard you as a "good" friend. So in this table there is a record: 10, 11, "good". But you think me as a normal friend, so one more record: 11, 10, "normal"
This is simply a declaration of two columns with similar attributes in the same line. It is similar to
t.string :user_id
t.string :friend_user_id
You can find the documentation for that in here (look for "Short-hand examples")