Ankit Kulshrestha
Ankit Kulshrestha

Reputation: 111

When to use attr:accessors in place of a permanent column in rails?

I'm creating my own website using Ruby on Rails. One thing that I've failed to comprehend is why and when to use attr:accessors in place of a permanent column for a model. For instance, let's say that I created a 'posts' model which would have a title, description and some content associated with it. Now should I do rails g model Post title:string description:text content:text or should I declare them as attr:accessible :title, :description, :content.

I'm not very experienced in rails, so please bear with me if this sounds too silly to you.

Upvotes: 1

Views: 521

Answers (2)

Richard Peck
Richard Peck

Reputation: 76784

To add to Pardeep's epic answer, you'll want to look at this RailsCast (RE "virtual attributes"):

enter image description here

attr_accessor basically creates a setter & getter method in the model.

Probably doesn't make any sense; what you have to remember is that each Rails model is a class. Classes form the backbone of object-orientated programming.

Since Ruby is object orientated, each time you do anything with the language, it expects classes to be invoked & manipulated. The basis of OOP is to load classes into memory & play with them; good write-up here.

In classic OOP, your classes would be hard-coded with a series of attributes:

class Mario
   def jump
     pos_y + 5
   end

   def pos_y
      # gets y val from the viewport
   end
end

This will allow you to send instructions to the program, in turn modifying the class:

@mario.jump

... this should modify the viewport etc in the way you defined within the class.

--

Rails is very similar to the above, except most of the attributes are defined by ActiveRecord;

#app/models/mario.rb
class Mario < ActiveRecord::Base
   # attributes from db include height, weight, color etc
end

Rails models allow you to call:

@mario = Mario.find x
@mario.height = "255"

... however, they don't allow you to create attributes which are stored in memory only.

For example...

#app/models/mario.rb
class Mario < ActiveRecord::Base
   attr_accessor :grown
end

The above will give you an instance value of grown, which will allow you to populate this independently of the database.

So say you wanted to...

@mario = Mario.find x
@mario.grown = true if params[:grown]
@mario.height += "150" if @mario.grown

Regarding the difference between attr_accessor and attr_accessible, you'll want to look up Rails 3 and mass assignment.

I came into Rails ~ 4.0, so I didn't have to deal with attr_accessible so much; it was basically the way to permit parameters in Rails 3 models.

In Rails 4/5, you use strong params in the controller:

#app/controllers/mario_controller.rb
class MarioController < ApplicationController
   def create
      @mario = Mario.new mario_params
      @mario.save
   end

   private

   def mario_params
      params.require(:mario).permit(:x, :y, :z)
   end
end

Upvotes: 0

Pardeep Dhingra
Pardeep Dhingra

Reputation: 3946

You can use attr_accessor if you need virtual attributes in model.

For eg: In contact us form you need not to see form data, but you need to send that data using email. So you can create attr_accessor for adding virtual attributes and can also apply validations on that.

class Contact
  include ActiveModel::Validations
  include ActiveModel::Conversion
  extend ActiveModel::Naming

  attr_accessor :name, :email, :content

  validates_presence_of :name
  validates_format_of :email, :with => /^[-a-z0-9_+\.]+\@([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i
  validates_length_of :content, :maximum => 500

  def initialize(attributes = {})
    attributes.each do |name, value|
      send("#{name}=", value)
    end
  end

  def persisted?
    false
  end
end

ref

attr_accessible is to white list of attributes that can be mass assigned in model.

class Comment < ActiveRecord::Base
  attr_accessible :user_id, :content
end

def create
  #so here params[:comment], have all parameters. But if those params are not in attr_accessible list it will not save it. 
  # you can try that by remove attr_accessible from model

  @comment = Comment.new(params[:comment])
  if @comment.save
    flash[:notice] = "Successfully created comment."
    redirect_to @comment
  else
    render :action => 'new'
  end
end

Comment Form:

<%= form_for @comment do |f| %>
  <%= f.error_messages %>
  <%= f.hidden_field :user_id, value: current_user.id %>
  <p>
    <%= f.label :content %><br />
    <%= f.text_area :content %>
  </p>
  <p><%= f.submit %></p>
<% end %>

Happy Coding...

Upvotes: 1

Related Questions