So, I'm building an app where I have a backend written in Rails and a client written in Vue with Amplify. My database is MySQL and I'm using AWS AppSync with a GraphQL as data source (pointing to my database).
The AWS Amplify has a framework that allows me to generate the schemas based on the table names and columns with one simple command: amplify api add-graphql-datasource
. But because I'm using rails migrations, my database is using Rails conventions: pluralized tables with snake cased columns.
Now, the problem with that is the GraphQL schemas are all ugly and not using the correct conventions (singular names for the types and inputs, with camel cased props). Example:
My backend has the following migration:
class CreatePosts < ActiveRecord::Migration[6.0]
def change
create_table :posts do |t|
t.belongs_to :site, null: false
t.string :title
t.string :url
t.text :body
t.timestamps
end
end
end
And the schema generated for this is:
type posts {
id: Int!
site_id: Int!
title: String
url: String
body: String
created_at: AWSDateTime!
updated_at: AWSDateTime!
}
type Query {
getPosts(id: Int!): posts
listPostss: [posts]
// ...
}
schema {
query: Query
// ...
}
Not to mention this:
input CreatepostsInput {
id: Int!
site_id: Int!
title: String
url: String
body: String
created_at: AWSDateTime!
updated_at: AWSDateTime!
}
So, AWS Amplify is new, it's not mature as Rails, and on top of that I didn't find any adapter or transformer to handle the problem in the client... my hope is to find a way to handle it on Rails.
I need to be able to completely change the Rails conventions without breaking anything: migrations, associations, how to manage associations (create_xxx, build_xxx).
This app is really new, so I can recreate all the migrations from scratch.
Thanks
I can see some things you can do:
Tables:
In your migration, you can change the table name, but now you need to let your model know what's the table name with self.table_name
.
# migration
class CreatePosts < ActiveRecord::Migration[6.0]
def change
create_table :post do |t| # singular 'post'
...
end
end
end
#model
class Post
self.table_name = "post" # i think you can also use a symbol :post
end
Attributes:
You need to avoid using Rails migration methods that follow Rails conventions like t.belongs_to
or t.references
or t.timestamps
.
# migration
class CreatePosts < ActiveRecord::Migration[6.0]
def change
create_table :post do |t|
# do not use this below
# t.belongs_to :site, null: false
t.bigint :siteId, null: false
t.string :title
t.string :url
t.text :body
# do not use this below
# t.timestamps
t.datetime :createdAt, default: ->{'CURRENT_TIMESTAMP'}
t.datetime :updatedAt, default: ->{'CURRENT_TIMESTAMP'}
end
end
end
Relationships:
You also need to update your relationships in your models
class Post
belongs_to :site, foreign_key: 'siteId'
end
More information can be found in the Rails API. Make sure you check the documenation for other relationship methods.
Timestamps:
Since timestamps columns (created_at
, updated_at
) are not the ones expected by ActiveRecord anymore, you might need to override the ActiveRecord::Timestamp
module to have them continue working as you would expect. One of the easiest option is to update your ApplicationRecord
or a single model class with the following:
class ApplicationRecord # or class Post
before_create :set_timestamps
before_save :set_timestamps
private
def set_timestamps
self.createdAt = DateTime.current if self.new_record?
self.updatedAt = DateTime.now
end
end
Or this other option taken from https://stackoverflow.com/a/52276865/1845602
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
class << self
private
def timestamp_attributes_for_create
super << 'my_created_at_column'
end
def timestamp_attributes_for_update
super << 'my_updated_at_column'
end
end
end
Auto generated Inputs:
I might be wrong here, but it seems the table name is being injected into the input name like Create<table>Input
, so if that's the case, you can name your table Post
instead of post
.
input CreatepostsInput {
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With