DEV Community

loading...

Using React-Redux to create the illusion of has_many

Alexander Rovang
Just a midwest boy in the Big Apple
・2 min read

So here was the problem: I had a single deck of cards and I wanted to remember the card(s) I pulled out at any given time, even AFTER putting the card(s) back in the deck.

My original thought was that this was a backend issue. A Draw has_many Cards, and a Card belongs_to a Draw.

class Draw < ApplicationRecord
   has_many :cards
end

class Card < ApplicationRecord
   belongs_to :draw
end

create_table "draws", force: :cascade do |t|
   t.string "card"
end

create_table "cards", force: :cascade do |t|
   t.string "name"
   t.integer "draw_id"
end
Enter fullscreen mode Exit fullscreen mode

But what if I didn't want a single Card to be permanently tied to a Draw? What if I wanted that relationship, but also wanted it to part of other Draws? So I added 'optional' to the relationship.

class Card < ApplicationRecord
   belongs_to :draw, optional:  true
end
Enter fullscreen mode Exit fullscreen mode

Which was closer... but it still made me uncomfortable thinking that the pristine deck of Cards sitting in my database would ever have a relationship with a single Draw. Enter React-Redux.

My thought was that a Draw doesn't need a specific Card, exactly, it needs the ID of a Card. So the first thing I did was change the schema.

create_table "draws", force: :cascade do |t|
   t.integer "card"
end
Enter fullscreen mode Exit fullscreen mode

Then on my frontend I created a method that give me a random number based on the length of an array and convert that number to an index in the array.

getRandomItem = (arr) => {
   const randomIndex = Math.floor(Math.random) * arr.length);
   const item = arr[randomIndex];
   return item.id;
}
Enter fullscreen mode Exit fullscreen mode

The, when submitting my form for a new Draw, I could call on this method and for the argument use the Card Array.

handleSubmit = (e) =>{
   e.preventDefault()
   let formData = {
      card: this.getRandomItem(this.props.cards)
   }
   this.props.createDraws(formData)
}
Enter fullscreen mode Exit fullscreen mode

This populated my Draw instance on the backend with a number that I saved as Draw.card. Then, when rendering a Draw back on the frontend I could just access that number and find the Card associated with it.

const Draw = props =>{
   let draw = props.draws.draws[props.match.params.id - 1]

   return(
      <div>
         Card Name: {draw && (props.cards.length > 0) ? <props.cards[draw.card - 1].name} : null
      </div>
   )
}
Enter fullscreen mode Exit fullscreen mode

And there you have it! A faux has_many relationship built almost entirely on the frontend of my app. Pretty sneaky React. Pretty sneaky.

Discussion (0)