The content of this article is currently awaiting review and may change!
Let literally one table be inherited from the parent class to the child class!
In this case, the parent Tweet
→ child Mediatweet
Texttweet
. Classes for media tweets and text tweets, respectively!
However, since the tables are the same, all classes, both parent and child, have the same columns.
So Mediatweet
also has a content
column, and ** Texttweet
also has a ʻimg` column. ** **
db/schema.rb
create_table "tweets", options: hogehoge
t.text "content"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.string "img"
t.integer "user_id"
t.string "type"
end
It will be easier to write the difference in the model. For example, if you write a validation with no blanks only in the texttweet, the image can be tweeted without text. However, since the contents are almost the same, STI that can share the table is good.
db / schema.rb
, but let the parent class (table) have a type
column (string type).rails g model
etc. and create the child model etc. directly in ʻapp / model /`models/tweet.rb
class Tweet < ApplicationRecord
end
models/mediatweet.rb
class Mediatweet < Tweet
end
models/texttweet.rb
class Texttweet < Tweet
end
For the time being, this is the end of STI implementation. The rest will be done automatically.
For example, if you register the database with Mediatweet.create
etc., a record containing Mediatweet
and data will be added to the type
column.
I want to sort the model automatically depending on whether there is media data, so I implemented it as follows.
index.html.erb
<%= form_with model: @tweet, url: tweets_path do |form| %>
<%= form.text_area :content %><br>
<%= form.label "Upload image" %><br>
<%= form.file_field :img %>
<%= form.submit 'Post' %><br>
<% end %>
This time, it is a post and list page that has a post form as it is in index.
The image uploader is implemented in carriewave
. I will omit that.
The parameters submitted by submitting from the above form are
{
"authenticity_token"=>"hoge",
"tweet"=>{"content"=>"hoge", "img"=>"hoge"},
"commit"=>"Post"
}
You can get the parameters of the double structure (structure with {} inside {}) like this.
And it automatically matches the create action of the controller
tweets_controller.rb
def create
@tweet = tweettype_class.new(tweet_params)
if @tweet.save
redirect_to("/tweets")
else
@tweets = Tweet.all.order(created_at: :desc)
render("index")
#Rendering returns to the original post list page At this time, form_If you don't specify the with url
#form_The root of with is pulled by the child model and an error occurs (eg)Former teats_path After rendering → text tweets_path is no much.
end
end
private
def tweet_params
#Only the part where the key is tweet is extracted by require({"content"=>"hoge","img"=>"hoge"})
params.require(:tweet).permit(:content, :img).merge(user_id: @current_user.id)
end
#[:img]Models are sorted according to the presence or absence of data
#Since it has a double structure, the value cannot be obtained correctly unless the key is also specified twice.
def tweettype
case
when params[:tweet][:img].present?
'mediatweet'
when params[:tweet][:img].blank?
'texttweet'
end
end
#Convert the received character string to camel case,Furthermore, it is converted to a constant name
#(Example) mediatweet.cmelize=>Mediatweet.constantize=>Mediatweet(id: integer, content: text, created_at: datetime, hogehoge.... )
def tweettype_class
tweettype.camelize.constantize
end
Like this, I tried to sort the models automatically depending on whether the image was uploaded.
This made it easier to write different roles for each model!