Lucas Andrade
Lucas Andrade

Reputation: 4580

Ruby add variables to an existing object?

How can I add variables to an existing obejct? I have a list of chat rooms and I want to add a new variable for each chat to use at my view:

Example I want to add total users of chat

def index
  chats_all = ChatRoom.all
  @chats = Array.new
  chats_all.each |chat|
    chat.total_users = 10
    @chats << chat
  end
  @chats
end

total_users is not an attribute of ChatRoom class.

[EDIT - explaim better after @jvillian great awnser]

I don't want total_users as an attribute of User class.
I just want to add as a variable to use at this one single page. For json rails already let my add new attributes to objects. Just need to use as_json().map and a merge()
Example:

def index
  chats = chats.as_json().map {
    |chat| 
    chat.merge(
      total_users: 10
    }
  response = { chats: chats }
  render json: response
end

Now I got an json with chats and each chat has total_users attribute.

I want to know if I can do something like this with objects, just add a temporary variable to use at index page.

Upvotes: 0

Views: 1128

Answers (3)

Lucas Andrade
Lucas Andrade

Reputation: 4580

To create temporary custom Objects without add new attributes to database Struct solve my problem.

I can create a Struct with chat room info and total users

chat_info = Struct.new(:name, :total_users, :messages)
chat_temp = []
chats = ChatRoom.where(condition)
chats.each do |chat|
  chat_temp << chat_info.new("nome", 100, messages)
end

Upvotes: 0

jvillian
jvillian

Reputation: 20263

Try

class ChatRoom < ActiveRecord::Base
  attr_accessor :total_users
end

You can read more in the docs.

Then, index could look like:

def index
  @chats = ChatRoom.all.map do |chat|
    chat.total_users = 10
    chat
  end
end

Alternatively, I would be tempted to do something like:

class ChatRoom < ActiveRecord::Base
  TOTAL_USERS = 10

  attr_accessor :total_users

  def total_users
    @total_users || TOTAL_USERS
  end
end

And then:

def index 
  @chats = ChatRoom.all
end

Now, you'll get

@chats.first.total_users
 => 10

You can set total_users to something else if you like, but it will default to 10.

Here's a potential approach using OpenStruct:

def index
  @chats = ChatRoom.all.map do |chat|
    OpenStruct.new(
      chat.
        attributes.
        merge!(total_users: 10)
    )
  end
end

Now, you can do:

@chats.each do |chat|
  puts chat.total_users
end

which will return 10.

BTW and TBH, I do something like that last sort of thing (using OpenStruct or custom decorators) all the time. In my more recent apps, views never have direct access to models.

Upvotes: 2

iGian
iGian

Reputation: 11193

Maybe you want to send the response to the view as an array and scan to show informations?

def index
  @chats = ChatRoom.all.as_json().map { |chat| chat.merge("total_users" => 10) }
end

Then access @chats, which is actually an array of hashes, view:

<% @chats.each do |chat| %>
  <p><%= chat["total_users"] %></p>
<% end %>

You can check how @chats is structured by <p><%= @chats %></p>

I maybe made some syntax error.

Upvotes: 0

Related Questions