Reputation: 1329
I am creating an API for serving up crossword puzzles. I am trying to stay pretty close to the JSON format proposed at XwordInfo. What I am having trouble with is transforming how I want it described in my models (client and server side) and how I want it in the database.
For example, take clues:
{
...
"clues": {
"across": [
"1. This is a clue",
"5. So is this"
],
"down": [
"1. This is a down clue",
"2. Here we go again."
]
}
...
}
Client-side puzzle model:
...
String title
Dictionary<String, Array> clues
String authore
...
Database:
create_table "clues", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
t.string "direction"
t.integer "crossword_id"
end
add_index "clues", ["crossword_id"], name: "index_clues_on_crossword_id", using: :btree
So I need to convert basically an array of clue name, direction objects (what's in the database) to a dictionary of clues which has 2 arrays, across and down. This seems like something that should be fairly common to have to do (transforming requests/responses) but I can't quite figure out how to search for it.
EDIT: I've already got the serialization part figured out with JBuilder: Here is how I display an array of clues:
crossword/index.json.jbuilder:
json.clues do
json.across @crossword.clues.reject { |clue| clue.direction != 'across' }.collect { |clue| clue.name}
json.down @crossword.clues.reject { |clue| clue.direction != 'down' }.collect { |clue| clue.name}
end
But coming from the user, how do I take that same dictionary > of clues and turn it into a list of Clue(name, direction,
Upvotes: 0
Views: 174
Reputation: 34774
I think you're just talking about iterating over the hash structure. Something like:
crossword = Crossword.find(id) # Or somesuch - not sure how you get the crossword
# Process across then down clues from the clues hash
["across", "down"].each do |direction|
# Iterate over the clues in the array for the given direction
clues[direction].each do |clue_text|
# Create a clue on the crossword with the given text and direction
crossword.clues.create!(name: clue_text, direction: direction)
end
end
That will certainly populate your clues model from the json. Providing of course you have a has_many clues
on your Crossword model (you seem to).
Aside 1: You might want to extend the model to include the number of the clue though because that implementation will not guarantee your clues are returned in order. This will obviously affect your serialization/deserialization though and you may end up with a hash for each clue. Or may it's enough to parse the clue text for the number.
Aside 2: You may also want to add a couple of direction class methods to your Clue
class to make it easier to retrieve down and across clues:
def self.down
where(direction: 'down')
end
def self.across
where(direction: 'across')
end
In your jbuilder you can then do:
@crossword.clues.down.collect(&:name)
Upvotes: 1
Reputation: 170
This is a great use case for a serializer. I like https://github.com/rails-api/active_model_serializers
You can create a serializer for the Crossword model that in turn will return an array of its clues, each of which is serialized by its own Clue serializer.
Upvotes: 1