Reputation: 6815
I have entries
table with a content
field which might contain a lot of text. In most cases I don't need to access that field, so it seems to be a big waste of resources to every time load a huge amount of unused data from the database (select * from entries where id = 1).
How could I specify the default_scope, that all the fields apart from content
would be loaded from database?
Upvotes: 6
Views: 3217
Reputation: 193
Its not a default scope, but I am using the following solution for my case:
scope :no_content, -> { select(self.column_names.map(&:to_sym) - [:content]) }
Add no_content
to the call is imo not a big deal, because you probably know which calls are a problem.
Upvotes: 0
Reputation: 462
As scoping, and default_scope mainly, gives many problems in use, my best way is to move big contents (binary, very large texts) to separate table.
create_table "entries", :force => true do |t|
t.string "title"
# ... more small sized attributes of entries
t.timestamps
end
create_table "entry_contents", :force => true do |t|
t.references :entries, foreign_key: true
t.text "content"
t.timestamps
end
class Entry ...
# reference
has_one :entry_content
# build entry_content for every new entry record
after_initialize do |entry|
entry.build_entry_content unless entry.entry_content.present?
end
end
This limits loading big data only when needed.
Entry.find(1).entry_content.content
Upvotes: 2
Reputation: 2213
To build on @phlipper answer's, if you want to just specify one or a few columns to get rid of:
class Entry < ActiveRecord::Base
default_scope { select(Entry.column_names.map!(&:to_sym) - [:metadata]) }
end
As you can see, as of Rails 5+ you have to pass a block to default_scope
.
Also, you should consider not using default scope
Upvotes: 1
Reputation: 1834
Assuming Rails 3 and a schema that looks like this:
create_table "entries", :force => true do |t|
t.string "title"
t.text "content"
t.datetime "created_at"
t.datetime "updated_at"
end
You can use the select
method to limit the fields that are returned like this:
class Entry < ActiveRecord::Base
default_scope select([:id, :title])
end
In the rails console, you should see something like this:
puts Entry.where(:id => 1).to_sql # => SELECT id, title FROM "entries" WHERE "entries"."id" = 1
When you do want to select all of the fields, you can use the unscoped
method like this:
puts Entry.unscoped.where(:id => 1).to_sql # => SELECT * FROM "entries" WHERE "entries"."id" = 1
Upvotes: 13