0

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.

7
  • It does not sounds clear to me. What's the existing object? And what variable do you want to add? Maybe you can build an hash @chats = {:'1' => {total_users: 10}, .... . Can you explain more? Commented Jun 14, 2018 at 20:42
  • "total_users is not an attribute of ChatRoom class" - sounds like it should be. Commented Jun 14, 2018 at 20:47
  • How exactly are you using total_users? This seems like it might be an XY problem. Commented Jun 15, 2018 at 3:08
  • @jvillian I am using in my view. At my .html.erb file I have @chats.each |chat| and than I display total_users Commented Jun 15, 2018 at 3:10
  • 2
    But total users is always 10? Commented Jun 15, 2018 at 3:34

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Good solution. But now it's an attribute of the class. Isn't it?
@iGian but only a "virtual attribute" not an attributes attribute used for persistence purposes. And rails 5 has actually implemented an API for this with type specification Nice Read
@jvillian thank you, but I don't want to add a new attribute to my class, I just want to add total_users to use at one single page. I will edit my question to explaim better. Sorry.
0

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.

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.