Using Rails 4
I am wondering (and having a hard time finding an answer) if it is OK to call an ActiveRecord method directly from the view, such as:
<%= Article.where(approved: true).count %>
or
<%= Article.where("short_answer is NOT NULL and short_answer != ''").count %>
I realize the normal practice would be to store these in an instance variable inside of the controller, but since I am using a partial, I cannot do that.
Is doing this ok? Can it hurt? Is there a better way to go about this (such as a helper method)? Thank you!
ActiveRecord is commonly used with the Ruby-on-Rails framework but you can use it with Sinatra or without any web framework if desired.
ActiveRecord is an ORM. It's a layer of Ruby code that runs between your database and your logic code.
Rails 6.0 ships with all the rails tasks you need to use multiple databases in Rails. Running a command like bin/rails db:create will create both the primary and animals databases.
ActiveRecord::Base indicates that the ActiveRecord class or module has a static inner class called Base that you're extending. Edit: as Mike points out, in this case ActiveRecord is a module... ActiveRecord is defined as a module in Rails, github.com/rails/rails/tree/master/activerecord/lib/…
Is doing this ok? Can it hurt?
It's definitely okay, but the problem is that you'll be calling another db query - which is the most "expensive" part of a Rails app.
@instance_variables
are set once, and can be used throughout the view:
#app/views/articles/show.html.erb
#Referencing @article references stored data, not a new DB query
<%= @article.title %>
<%= @article.description %>
<%= @article.created_at %>
Because the above all uses the stored @article
data, the database is only hit once (when @article
is created in the controller).
If you call AR methods in the view, you're basically invoking a new db call every time:
#app/views/articles/show.html.erb
#Bad practice
<%= Article.select(:name).find(params[:id]) %>
<%= Article.select(:description).find(params[:id]) %>
<%= Article.select(:created_at).find(params[:id]) %>
To answer your question directly, you would be okay to call that data IF you were only counting database-specific data.
IE if you were trying to count the number of @articles
, you'd be able to call @articles.size
(ActiveRecord: size vs count)
The prudent developer will determine which data they have in their controller, and which they need to pull from the db... doing all their db work in the controller itself:
#app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
def index
@articles = Article.where(approved: true) #-> could use a scope here if you wanted
end
end
#app/views/articles/index.html.erb
<%= @articles.size %>
Nithin
's answer is great but won't get past the consideration that you have to determine whether you need to call the db explicitly, or use already-invoked data.
Finally, in regards to using a partial, if you have to pass that data every time, you may wish to use some sort of conditional data to determine whether you need to call the db or not:
#app/views/shared/_partial.html.erb
<% approved ||= Article.approved_articles.size %>
<% short ||= Article.short_answer_presence.size %>
This will allow you to set locals IF you want, and also have "defaults" set if they aren't set.
You should mostly do
class Article < ActiveRecord::Base
....
scope :approved_articles, where(approved: true)
scope :short_answer_presence, where("short_answer is NOT NULL and short_answer != ''")
end
In your controller method
@approved_articles_count = Article.approved_articles.count
@short_answer_presence_count = Article.short_answer_presence.count
and use those variables in view.
In case of partials, as said my Raman you can do that.
<%= render partial: "form", locals: {approved_articles_count: @approved_articles_count, short_answer_presence_count: @short_answer_presence_count} %>
You can always pass these variables inside a partial using locals:
<%= render partial: "form", locals: {zone: @zone} %>
Its always a good practice to define the instance variables in controller, it does not hurt but you don't end up doing business logic inside a view.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With