エラーメッセージを日本語で表示
1. error messageを日本語にする
//jaの記述でja.ymlが読み込める config.i18n.default_locale = :ja //localesディレクトリ配下のファイル読み込む config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.yml').to_s]
- エラーメッセージがname属性以外日本語になる
2. name属性も日本語にする
//サンプル ja: activerecord: attributes: post: title: 'タイトル' article_text: '記事テキスト' status_id: '公開/非公開' category_id: 'カテゴリー' images: '画像' user: nickname: 'ニックネーム' last_name: '苗字' first_name: '名前' profile: 'プロフィール'
rails cでテスト
pry(main)> I18n.t("activerecord.attributes.user.nickname") => "ニックネーム" pry(main)> I18n.t("activerecord.attributes.post") => {:title=>"タイトル", :article_text=>"記事テキスト", :status_id=>"公開/非公開", :category_id=>"カテゴリー", :images=>"画像"}
- 同ディレクトリにdevise.ja.yml 作成(コピペ)
参考:devise.ja.yml
実装結果 gyazo.com
■
SQLで中間テーブルを含めて3つのテーブルを結合してみた
今回結合したのは、
Posts、Tags、PostTagRelationsの3つのテーブル
最終目的:Tagsテーブルのnameカラムのvalueの値
3つのテーブル結合した図
select * の部分*(ワイルドカード” * ”を指定)で全てを指定している
gyazo.com
カラムをPosts.nameとTags.name指定してみた図
だいぶすっきり
gyazo.com
実際には、select t.name form~だけでいいのでさらに絞ってます
rails cで見てみる
- 実際に値を取得し、変数sqlに代入
- モデル.find_by_sql(変数)で出力する =>配列になってる gyazo.com
- 変数に手順2のfind_by_sqlを代入する
- 変数[0].カラム名で出力する =>今回は,@tag_name[0].name
posts.controller.rb
def edit @post = Post.find(params[:id]) //@form = PostsTag.new(title: @post.title, article_text: @post.article_text, status_id: //@post.status_id, category_id: @post.category_id, user_id: current_user.id, post_id: @post.id,image: @post.image) sql = "SELECT t.name FROM posts p JOIN post_tag_relations ptr ON p.id = ptr.post_id JOIN tags t ON ptr.tag_id = t.id WHERE p.id = #{@post.id}" Tag.find_by_sql(sql) end
text_fildeにvalue: @tag_name[0].nameで表示させました
edit.html
<%= form_with model: @form, url: post_path, method: :put, local: true do |f| %> <div class="tag-field", id='tag-field'> <%= f.label :name, "タグ" %><br /> <%= f.text_field :name, value: @tag_name[0].name,class:"input-tag" %> </div> <div id="search-result"> </div> <% end %>
データが1件でもあるかチェックする
exists?
指定した条件のレコードがデータベースに存在するかどうかを真偽値で返すメソッドです。存在すればtrueを存在しなければfalseを返します。
1件でもあればtrueを返す
オブジェクト.exists?(条件)
例:
> User.exists? User Exists (3.0ms) SELECT 1 AS one FROM "users" LIMIT $1 [["LIMIT", 1]] => true
条件つき
User.exists?(id: [1, 2, 3], name: 'opiyo', role: 'admin')
今回の自身のコード
今回はusers#indexで条件付きでexists?の返り値を@post_userに代入し、viewのif分岐の条件に記述しました
* 条件分岐
<if ログインしているか> <if ログインしたユーザーの投稿があるか> <if ログインしたユーザーの投稿> //ユーザーの投稿内容のみ表示 <end> <else> //ログインユーザーの投稿がない hogeさんの投稿がありません //全てのユーザーの投稿内容表示 <end> <else> ログインしてません //全てのユーザーの投稿内容表示 <end>
実際のコード
<% if user_signed_in? %> <% if @post_user %> //コントローラからtrueまたはfalseを受け取る <% @posts.each do |post| %> <% if post.user_id == current_user.id %> <div class="post_wrap"> <div class="card"> <div class="article_card"> <%= link_to "タイトル:「#{post.title}」", post_path(post.id), class: :card__title %> <ul class="tag"> <li class="tag_ribbon"> <%post.tags.each do |tag| %> #<%=tag.name%> <% end %> </li> </ul> <div class="status"> <%= post.status.name%> </div> <%= link_to image_tag(post.image, class: :card__img), post_path(post.id) %> <div class="date"> <div class="image-month">12</div> <div class="image-year">2020</div> </div> </div> </div> </div> <% end %> <% end %> <% else %> <p>まだ投稿していません</p> <h1>みんなの投稿</h1> <% end %> <% else %> <%# ログインしていない %> <h1>みんなの投稿</h1> <% end %>
- コントローラー
//users_controller class UsersController < ApplicationController def index @posts = Post.all.order(created_at: :desc) @post_user = Post.exists?(user_id: current_user.id) //trueまたはfalseを代入 end end class PostsController < ApplicationController before_action :set_post, only: [:show, :edit, :update] //----------------------------------------------------------- //users_controller def index @posts = Post.all.order(created_at: :desc) end end
【Rails】exists?メソッドの使い方(基礎~応用編,prese | Pikawaka - ピカ1わかりやすいプログラミング用語サイト
gemを使わない tag機能の実装
詳しく後日編集します
ポイント
中間テーブル
複数のテーブルを同時にcreateするモデルを使用
jsでajax通信
updateする
model
アソシエーションの記述
model/post.rb
class Post < ApplicationRecord belongs_to :user has_many :post_tag_relations, dependent: :destroy has_many :tags, through: :post_tag_relations has_one_attached :image extend ActiveHash::Associations::ActiveRecordExtensions belongs_to :status end
model/post.rb
class Tag < ApplicationRecord has_many :post_tag_relations, dependent: :destroy has_many :posts, through: :post_tag_relations //一意性のバリデーションはここに記述 validates :name, uniqueness: true end
model/post_tag_relation.rb
class PostTagRelation < ApplicationRecord belongs_to :post belongs_to :tag end
model/posts_tag.rb
ここに同時保存の内容を記述(マイグレーションファイルはいらないので、rails gで作成しないで手作業で生成する)
class PostsTag include ActiveModel::Model attr_accessor :title, :article_text, :status_id, :category_id, :image, :name, :user_id, :post_id with_options presence: true do validates :title , length: {maximum: 20} validates :article_text , length: {maximum: 300} validates :status_id , numericality: {other_than: 1, message: "は--以外から選んでください"} validates :category_id , numericality: {other_than: 1, message: "は--以外から選んでください"} validates :name validates :image end def save post = Post.create(title: title, article_text: article_text, status_id: status_id, category_id: category_id, image: image, user_id: user_id) tag = Tag.where(name: name).first_or_initialize tag.save PostTagRelation.create(post_id: post.id, tag_id: tag.id) end def update binding.pry @post = Post.where(id: post_id) post = @post.update(title: title, article_text: article_text, status_id: status_id, category_id: category_id, image: image, user_id: user_id) tag = Tag.where(name: name).first_or_initialize tag.save map = PostTagRelation.where(post_id: post_id) map.update(post_id: post_id, tag_id: tag.id) end end
コントローラー
class PostsController < ApplicationController before_action :set_post, only: [:show, :edit, :update] def index @posts = Post.all.order(created_at: :desc) end def new @post = PostsTag.new end def create @post = PostsTag.new(post_params) if @post.valid? @post.save return redirect_to root_path else render :new end end def edit @form = PostsTag.new(title: @post.title, article_text: @post.article_text, status_id: @post.status_id, category_id: @post.category_id, user_id: current_user.id, post_id: @post.id,image: @post.image) end def update @form = PostsTag.new(update_params) if @form.valid? @form.update redirect_to root_path else render :edit end end def tag_search return nil if params[:keyword] == "" tag = Tag.where(['name LIKE ?',"%#{params[:keyword]}%"] ) render json:{ keyword: tag } end private def post_params params.require(:posts_tag).permit(:title, :article_text, :status_id, :category_id, :image, :name).merge(user_id: current_user.id) end def update_params params.require(:posts_tag).permit(:title, :article_text, :status_id, :category_id, :image, :name).merge(user_id: current_user.id, post_id: params[:id]) end def set_post @post = Post.find(params[:id]) end end
PostsTagで同時保存
class PostsTag include ActiveModel::Model attr_accessor :title, :article_text, :status_id, :category_id, :image, :name, :user_id, :post_id with_options presence: true do validates :title , length: {maximum: 20} validates :article_text , length: {maximum: 300} validates :status_id , numericality: {other_than: 1, message: "は--以外から選んでください"} validates :category_id , numericality: {other_than: 1, message: "は--以外から選んでください"} validates :name validates :image end def save post = Post.create(title: title, article_text: article_text, status_id: status_id, category_id: category_id, image: image, user_id: user_id) tag = Tag.where(name: name).first_or_initialize tag.save PostTagRelation.create(post_id: post.id, tag_id: tag.id) end def update binding.pry @post = Post.where(id: post_id) post = @post.update(title: title, article_text: article_text, status_id: status_id, category_id: category_id, image: image, user_id: user_id) tag = Tag.where(name: name).first_or_initialize tag.save map = PostTagRelation.where(post_id: post_id) map.update(post_id: post_id, tag_id: tag.id) end end
view(posts/new.html)
※ edit.htmlには@formを渡してます
<%= form_with model: @post, url: posts_path, local: true do |f|%> <%= render 'shared/error_messages', model: f.object %> <div class="field"> <%= f.label :status_id, "公開/非公開 必須" %><br /> <%= f.collection_select(:status_id, Status.all, :id, :name, {class:"genre-select"}) %> </div> <div class="field"> <%= f.label :category_id, "カテゴリー 必須" %><br /> <%= f.collection_select(:category_id, Category.all, :id, :name, {class:"genre-select"}) %> </div> <div class="tag-field", id='tag-field'> <%= f.label :name, "タグ" %> <%= f.text_field :name, class:"input-tag" %> </div> <div id="search-result"> </div> <div class="field"> <%= f.label :title, "記事タイトル" %><br /> <%= f.text_field :title, id:"article_title" %> </div> <div class="field"> <%= f.label :image, "投稿画像" %><br /> <%= f.file_field :image, id:"post_image" %> </div> <div class="field"> <%= f.label :article_text, "記事テキスト" %><br /> <%= f.text_area :article_text, class: :form__text, id:"prototype_catch_copy" %> </div> <div class="actions"> <%= f.submit "保存する", class: :form__btn %> </div> <% end %>
where likeであいまい検索!
form_withでurlとmodelを同時に記述する理由
- 入力された情報をデータベースに保存しない時の記述です
<%= form_with url: "パス" do |form| %> フォーム内容 <% end %>
- 入力された情報をデータベースに保存する時の記述です
<%= form_with model: モデルクラスのインスタンス do |form| %> フォーム内容 <% end %>
urlとmodelを同時に記述する
以下は、url: donations_pathという記述で送信先のpathを明示する必要があります。urlオプションでpathを明示しないと、form_withはmodelオプションで渡されたモデル名をもとに自動的にpathを判断してしまうためです。
<%= form_with(model: @user, url: donations_path, local: true) do |form| %> <h1>ユーザー名を入力してください</h1> <div class="field"> <%= form.label :name, "名前(全角)" %> <%= form.text_field :name %> </div> <div class="field"> <%= form.label :nickname, "ニックネーム(半角英数)" %> <%= form.text_field :nickname %> </div> <div class="actions"> <%= form.submit "寄付する" %> </div> <% end %>
railsで特定のマイグレーションファイルをロールバックする
サンプル
Status Migration ID Migration Name -------------------------------------------------- up 20210317022552 Devise create users up 20210317030520 Create sns credentials down 20210318031327 Create posts down 20210318044136 Create active storage tablesactive storage down 20210326063233 Create tags down 20210326063303 Create post tag relations
コマンド
// マイグレーションファイルの状態を確認 % bundle exec rake db:migrate:status // upのファイルをdownにし、再編集できる bundle exec rake db:migrate:down VERSION='upのマイグレーショID'
rails db:rollbackだと1つまえのファイルしか戻せないのでだいぶ前のファイルは上記の方がいいと思います