Is it possible to add the time when a certain article was edited or created through the administration framework, using rails?
By adding the time, I mean when some user reads that article on the website, he can also read the last time it was edited or created.
I know I can add it manually, but I want to make it automatic.
Thank you!
By default, every Rails generated model includes timestamps called created_at and updated_at which correspond to when the record was initially created (added to the DB) and last updated.
As long as your migration to create the model has the following line, then the timestamp functionality will be enabled
class CreateProducts < ActiveRecord::Migration[5.0]
def change
create_table :products do |t|
# ...
t.timestamps
end
end
end
Resources:
http://api.rubyonrails.org/classes/ActiveRecord/Timestamp.html
http://guides.rubyonrails.org/active_record_migrations.html
Related
with what migration can I add a column to every model at once? This would be handy almost every time you forgot to add a field anyway because most of the time a field you want to add is not limited to one model only. Like "email" In this case I forgot to add an "order" field.
Thanks
You can do as follows -
def change
tables = [:users, :products, :addresses]
tables.each do |table_name|
add_column table_name, :order, :integer
end
end
It's called a group migration
Answering your first question "With what migration can I add a column to every model at once?". Answer: None. Rails migrations are a way to alter database schemas over time in a consistent way.
Rails migrations are Ruby classes using Rails methods as instructions to modify your database as needed. So your question could be better formulated as "How can I create a migration to add a column to every model at once?"
IMHO I don't think there's going to be a specific method to do this, as the requeriment is pretty custom, but, depending in your Rails version you can get all the ApplicationRecord.descendants:
Zeitwerk::Loader.eager_load_all
ApplicationRecord.descendants.map { |table| table.name.downcase.pluralize }.each do |table|
add_column table, :logdate, :datetime
end
Or all those tables from the database that can be safe_constantized:
ActiveRecord::Base.connection.tables.map do |table|
table.classify.safe_constantize
end.reject(&:nil?).each do |table|
add_column table, :logdate, :datetime
end
That way you get the name of each table/model and use it as the first argument for add_column.
The difference is that in Rails 6 the default code loader is Zeitwerk, so you can eager load all the project dependencies. In other versions you could do the same but using Rails.application.eager_load!.
The second version would work without having to load the models as dependencies as it makes a query asking for their tables and then maps them as constants.
I need to generate a migration that creates a table called creditcardquotas, but rails generate a table called credit_card_quota exactly like the name of the model.
I tried with the method pluralize
helper.pluralize(2, 'quota')
=> "2 quota"
class CreateCreditCardQuota < ActiveRecord::Migration
def change
create_table :credit_card_quota do |t|
t.integer :credit_card_id
t.integer :quotes
t.integer :interest
t.timestamps
end
end
end
How do I tell Rails migration that I want that the table called credit_card_quotas?
Create a file in config/initializers/. Name that file inflections.rb and add this content in it.
Before adding you get:
helper.pluralize(2, 'quota')
=> "2 quota"
Add the inflection:
ActiveSupport::Inflector.inflections do |inflect|
inflect.plural 'quota', 'quotas'
end
After that:
helper.pluralize(2, 'quota')
=> "2 quotas"
You can add any kind of valid or invalid pluralizations in this file...
Run the migrations after having applied this configuration change.
In my recent experience, it seems like rails/active record does not know how to pluralize the word "quota", or that it thinks that the plural of the word "quota" is "quota". I just tried to create a new migration for a "quotas" table that was paired with a Quota class in quota.rb. In rails console, when trying to use this model, I saw this warning:
Quota(Table doesn't exist)
But when I updated my Quota class to be Quotas and renamed the file, I was able to use the quotas table in the db. My eventual solution was to change the db table name from quotas to quota and use the Quota class for my model.
I am developing on RoR 4, with Oracle, PostGreSQL and MSSQL as target databases.
I am building a hierarchy of 4 objects, for which I need to display parent-child relationships through the same query whatever level I start from. Not easy to figure out, but the hint is that none of the object should have identical IDs.
The issue here is that rails maintains a dedicated sequence for each object, so duplicated IDs will appear for sure.
How can I create a sequence to fill a unique_id field which remains unique for all my data ?
Thanks for your help,
Best regards,
Fred
I finally found this solution:
1 - create a sequence to be used by each of concerned objects
class CreateGlobalSequence < ActiveRecord::Migration
def change
execute "CREATE SEQUENCE global_seq INCREMENT BY 1 START WITH 1000"
end
end
2 - Declare this sequence to be used for identity columns in each of concerned models
class BusinessProcess < ActiveRecord::Base
self.sequence_name = "global_seq"
...
end
class BusinessRule < ActiveRecord::Base
self.sequence_name = "global_seq"
...
end
and so on. It works fine.
Rails is great !
Thanks for your help, and best regards,
Fred
Id column for each table is unique identifier for each table record. It will not make any impact on other table Id column.
Don't know why you need this. But you can achieve it by some extent. Like below :
class CreateSimpleModels < ActiveRecord::Migration
def self.up
create_table :simple_models do |t|
t.string :xyz
t.integer :unique_id
t.timestamps
end
execute "CREATE SEQUENCE simple_models_unique_id_seq OWNED BY
simple_models.unique_id INCREMENT BY 1 START WITH 100000"
end
def self.down
drop_table :simple_models
execute "DELETE SEQUENCE simple_models_unique_id_seq"
end
end
But after 100000 record in db it will again going to similar for other model.
The default id column has the identity attribute, which is stored per-table. If your models fit the bill for Single Table Inheritance you'd be able to define a custom id attribute on the base class. In your case since you said it's a hierarchy that might be the way to go.
The harder? (STI is a bit to digest but very powerful) way of doing this involves what I'm working on this similar issue with a shared PAN (Private Account Number in this system) in a shared namespace.
class CreatePans < ActiveRecord::Migration
def change
create_table :pans do |t|
t.string :PAN
t.timestamps
end
end
end
class AddPanIdToCustomers < ActiveRecord::Migration
def change
add_column :customers, :pan_id, :integer
end
end
The first migration will add the ID table, the second adds the foreign key to the customers table. You'll also need to add the relationships to the models has_many :pans and belongs_to :customers. You can then refer to their identity by the :pan_id attribute (however you name it). It's a roundabout way of doing things, but in my case business requirements force it - hacky as it is.
I have a model, lets call it Posts.
Posts has a Date-field referring to a date other that created_on, updated_on e tc,
Lets call this field custom_date.
When a user creates a post and inputs the custom_date field the POST will look like
params[:post][:custom_date] = "04/12/2013 01:01"
this is referring to day/month/year hour:minute.
When I call
#post= Post.new(post_params)
And then inspect #post the custom_date have been reformated to 2013-12-04 , without the hour and minute. I guess the format is the datebase (correct me if im wrong) way of storing the Date.
But, I want to get the hour and minute in here. So I figured that I could make this happen in a clean way in the model file:
private
def fix_dates_from_input
self.start_date = DateTime.parse(self.custom_date) unless start_date.custom_date?
render text: self.inspect
end
And call this before validation:
before_validation :fix_dates_from_input
How ever, it seems the date is formated when it gets to the model, so that I can't change it there (becouse I dont have the minute or hour data).
I was hoping that I could do this outside of the controller,
Is there another way?
It is likely that your database is only storing the date and not the datetime.
Check the db/schema.rb file to see if this is the problem. If this is the issue, it will say something like:
create_table :posts do |t|
...
t.date :custom_date
...
end
When it should look like this:
create_table :posts do |t|
...
t.datetime :custom_date
...
end
To fix this you will either want to go back and fix the original migration (if it is a new project), or if you do not have the luxury of rebuilding your database from scratch, create a new migration to fix the problem:
From command line:
rails g migration change_custom_date_type
Then edit that file:
class ChangeCustomDateType < ActiveRecord::Migration
def change
change_column :posts, :custom_date, :datetime
end
end
I have a migration that creates a table, and I need to access the model for that table to create another table. The migration seems to not recognized that the original table has been created, so to make sure I put a debugger in my code and when I get to the model call, it says User(Table doesn't exist) even though in mysql I see it being created.
Looks like migrations can't see the current state of the database, any ideas how to get around that?
Just to be more specific about my question:
I'm trying to use Archivist to create archive of my current User table so I have
class ArchivedHeuristicReviewsTable < ActiveRecord::Migration
def self.up
create_table "users" do |t|
t.string "name"
...
end
debugger
Archivist.update User
end
def self.down
drop_table :users
drop_table :archived_users
end
end
the Archivist, doesn't create the archived_user table, so when I stopped at debugger and did User, I got User(Table doesn't exist).
I even tried Archivist call in a newer migration, so to make sure User creation is all done, but it still didn't recognize the user table.
Any ideas?
This should do the trick:
User.connection.schema_cache.clear!
User.reset_column_information