Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails: Is it ok to call ActiveRecord Methods in the view Rails

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!

like image 254
Kathan Avatar asked Dec 20 '15 02:12

Kathan


People also ask

Can you use ActiveRecord without Rails?

ActiveRecord is commonly used with the Ruby-on-Rails framework but you can use it with Sinatra or without any web framework if desired.

Is ActiveRecord an ORM?

ActiveRecord is an ORM. It's a layer of Ruby code that runs between your database and your logic code.

How can we use two databases to a single application Rails?

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.

What is ActiveRecord :: Base in Rails?

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/…


3 Answers

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.

like image 112
Richard Peck Avatar answered Oct 23 '22 16:10

Richard Peck


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} %>
like image 40
Nithin Avatar answered Oct 23 '22 18:10

Nithin


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.

like image 1
Raman Avatar answered Oct 23 '22 17:10

Raman