0

In my index action I am creating an instance variable like so:

def index
  @cards = Card.where(:cardstack_id => params[:cardstack_id])
end

This creates the output for @cards:

[#<Card id: 3, header: "Crazy", body: "Lege deinen Kopf für zwei Minuten auf den Tisch un...", points: 1, cardstack_id: 1, created_at: "2017-06-09 16:41:09", updated_at: "2017-06-13 17:24:29", lifetime: 240>, #<Card id: 4, header: "Böse Zungen", body: "Sprich 20 Minuten in einem starken Dialekt, der un...", points: 3, cardstack_id: 1, created_at: "2017-06-09 16:42:11", updated_at: "2017-06-13 17:26:24", lifetime: 360> ...

What I want to do now is to add for each object a random token created with SecureRandom.uuid.

So my output should look like this:

[#<Card id: 3, header: "Crazy", token: "34985jlskd908tjkls980", body : "..." ...]

How can I achieve this? I guess I have to somehow loop through the array in my controller, create a token for each element and then add it to a new array. However, I don't know how to achieve this.

Oliver
  • 1,181
  • 2
  • 12
  • 30
  • Do you need to update all your cars adding the token? – Sebastián Palma Jun 13 '17 at 20:41
  • I want to create a unique token for each card and then show each card with the unique token in my view (with @cards.each do |card| etc.). I figured out how to to this in the view, however for my purposes it is important that the token is saved in the instance variable (so at controller level). – Oliver Jun 13 '17 at 20:42
  • Could it be made in the rails console?, then in your controller you just select the Cards adding the token and the other attributes? – Sebastián Palma Jun 13 '17 at 20:43
  • Can those tokens be stored in the db? If so, use a callback in your model (i.e. `before_save`). – Gerry Jun 13 '17 at 20:46

2 Answers2

1

I guess I have to somehow loop through the array in my controller, create a token for each element and then add it to a new array. However, I don't know how to achieve this.

You won't be able to do this and keep a ActiveRecord::Relation object (which is the result of your query); but you could get an array of hashes, where each hash will contain all attributes (and values) for each record, including any new key you need to add, for example:

@cards = @cards.map { |i| i.attributes.symbolize_keys.merge({ token: SecureRandom.uuid }) }

Using your example, this will be the content for @cards:

[
  {
    :id=>3,
    :header=>"Crazy", 
    :body=>"Lege deinen Kopf für zwei Minuten auf den Tisch un...", 
    :points=>1, 
    :cardstack_id=>1, 
    :created_at=>"2017-06-09 16:41:09", 
    :updated_at=>"2017-06-13 17:24:29", 
    :lifetime=>240,
    :token=>"fa637bfa-a781-4029-8f60-2763e75d6d5c"
  },
  {
    :id=>4, 
    :header=>"Böse Zungen", 
    :body=>"Sprich 20 Minuten in einem starken Dialekt, der un...", 
    :points=>3, 
    :cardstack_id=>1, 
    :created_at=>"2017-06-09 16:42:11", 
    :updated_at=>"2017-06-13 17:26:24", 
    :lifetime=>360,
    :token=>"2ff962cf-2258-4f2a-8d50-d8a864fb845a"
  }
]

Then, you can iterate in your view just like any array, for example:

<% @cards.each do |card| %>
  <p>ID: <%= card[:id] %></p>
  <p>Header: <%= card[:header] %></p>
  ...
  <p>Token: <%= card[:token] %></p>
<% end %>
Gerry
  • 10,337
  • 3
  • 31
  • 40
  • Ok this looks really nice. Sorry for my noob question, but how can I now iterate over it in my view like I would do with the ActiveRecord Relation (like @cards.each do |card| etc.)? I want to show this data e. g. in a table. – Oliver Jun 13 '17 at 21:34
  • @Oliver You an do it like with any array, just consider that each element is a hash. Check updated answer. – Gerry Jun 13 '17 at 21:48
  • Awesome! Exactly what I was looking for (you have to add %> in each

    tag. Thanks a lot!

    – Oliver Jun 13 '17 at 21:53
0

It looks like you want to generate a UUID value for each card so that you can use it as a public id value without exposing the db id. Is that correct?

In that case, you shouldn't be doing it here. This should be done in after_initialize.

class Card < ActiveRecord::Base
  after_initialize do
    self.token ||= SecureRandom.uuid if has_attribute?(:token)
  end
end

Use of has_attribute? is necessary here in case you constrain the lookup with select and don't include token in the query.

Make sure you read up on the performance impacts of UUIDs in databases.

I ended up using this pattern for so many things I wrote a simple gem for it.

class Card < ActiveRecord::Base
  safe_initialize :token, with: ->{ SecureRandom.uuid }
end
Adam Lassek
  • 35,156
  • 14
  • 91
  • 107