krebas
krebas

Reputation: 45

Passing an instance variable from a model to a view

Hello (hopefully) omniscient Rails folks ;)

I'm currently trying to generate a set of radio buttons from an instance variable in one of my models. Because the MVC pattern prohibits passing data from models directly into the views, I somehow have to include the controller as kind of a middleman. The problem is that I can't access the instance variable of my model even though I use 'attr_reader :valid_statuses'. Therefore it's also not possible to pass the data down to my view...

This is how my user model looks like at the moment. The '@valid_statuses' array contains the strings which should be used to generate the radio buttons.

class User < ApplicationRecord
  attr_reader :valid_statuses
  @valid_statuses = %w(new editor admin blocked)
  validates :status, inclusion: { in: @valid_statuses }
end

The controller looks like this. @user is not nil, but @valid_statuses is

class UsersController < ApplicationController
  ...
  def set_user
    @user = User.find(params[:id])
    @valid_statuses = @user.valid_statuses
  end
  ...
end

The _form.html.erb:

<div class="field">
  <%= f.label :status %>
  <% @valid_statuses.each do |item| %>
    <%= f.radio_button :status, item %> <%= item %><br />
  <% end %>
</div>

I would be very greateful if someone knows the answer to this and could share it with me and the rest of the world! Thanks!

Upvotes: 1

Views: 690

Answers (2)

Eric Duminil
Eric Duminil

Reputation: 54213

Valid statuses don't change from one User to another.

So you define @valid_statuses inside the class User. @valid_statuses isn't defined for a specific @user, but for the whole class. attr_reader :valid_statuses tries to find the instance variable @valid_statuses of @user, which hasn't been defined.

Here's a possible modification :

class User < ApplicationRecord
  @valid_statuses = %w(new editor admin blocked)
  validates :status, inclusion: { in: @valid_statuses }
  def self.valid_statuses
    @valid_statuses
  end
end

and in your views :

User.valid_statuses

Upvotes: 1

Oleh  Sobchuk
Oleh Sobchuk

Reputation: 3722

in this case, you have to use constants (if you wanna only fix your code):

model:

class User < ApplicationRecord
  VALID_STATUSES = %w(new editor admin blocked)
  validates :status, inclusion: { in: VALID_STATUSES }
end

controller:

class UsersController < ApplicationController
  ...
  def set_user
    @user = User.find(params[:id])
  end
  ...
end

view:

<div class="field">
  <%= f.label :status %>
  <% User::VALID_STATUSES.each do |item| %>
    <%= f.radio_button :status, item %> <%= item %><br />
  <% end %>
</div>

BUT I better use enum with name status:

model:

class User < ApplicationRecord
  enum status: [:new, :editor, :admin, :blocked]
end

READ NORE ABOUT ENUMs

Upvotes: 1

Related Questions