Rails5: Semantic UIを使用する

Semantic UIとはBootstrapのようなWebフレームワーク.

参考サイト:
Semantic UIをRails5.1に導入するためにやったこと - Qiita

Gemfileファイル

[Gemfile]

gem 'semantic-ui-sass', git: 'https://github.com/doabit/semantic-ui-sass.git'
gem 'jquery-rails'

Semantic UIはjQueryを使用するのでjQueryも一緒にGemfileに記載してbundle intallを実行

$ bundle install

scssファイル

[app/assets/stylesheets/application.css]のファイル名を.cssから.scssに変更し、以下を追加.

$import-google-fonts: false;
@import 'semantic-ui';

javascriptファイル

[app/assets/javascripts/application.js]に以下を追加する.

//= require jquery
//= require jquery_ujs
//= require rails-ujs
//= require turbolinks
// Loads all Semantic javascripts
//= require semantic-ui
//= require_tree .

以上

公式サイト

公式ドキュメントは以下.
semantic-ui.com

Ruby on RailでBootstrap を使用する

参考サイト
Ruby on Rails チュートリアル:実例を使って Rails を学ぼう初めてのRuby on rails Bootstrap導入編 [Memo for neko] - Qiita


GemfileへのBootstrap追加

[app/gemfile]

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 5.1.6'
# bootstrap
gem 'bootstrap', '~> 4.1.1'

gem 'bootstrap'を追加して bundle install .

$ bundle install

application.cssの編集

ファイル拡張子をscssに変更し、ファイルの最後に@importを追加
[/app/assets/stylesheets/application.css] -> [/app/assets/stylesheets/application.scss]

 @import "bootstrap";

application.jsの編集

[app/assets/javascripts/application.js]

//= require bootstrap


以上!

使ってみる

適当にscaffoldして、migrate実行.

$ rails generate scaffold City name:string population:integer
$ rails db:migrate

Before
キャプチャ
f:id:Kurorera:20190531025605p:plain:w300
コード

<p id="notice"><%= notice %></p>

<h1>Cities</h1>

<table>
  <thead>

After
キャプチャ
f:id:Kurorera:20190531030200p:plain:w600
コード

<p id="notice"><%= notice %></p>

<h1>Cities</h1>

<table class="table">
  <thead class="thead-dark">

Bootstrapのcssが反映されている.

Rails: "has_many", "blongs_to"でリレーショナルなテーブル関係を設定する_コントローラ、ビュー実装

前回、以下にて"has_many", "blongs_to"でリレーショナルなテーブル関係を設定したので実際に使えるようにコントローラとビューへ実装する.
teki-com.hateblo.jp


参考サイト
has_manyとbelongs_toについて。モデルの関連付けされたformの作り方 - Qiita
第11章ユーザーのマイクロポスト - Railsチュートリアル
html - No route matches missing required keys: [:id] - Stack Overflow
Rails のルーティング - Rails ガイド
RailsのScaffoldでネストしたResourceを作る - sometimes I laugh
ネストした form_with のリダイレクト先がエラーになってしまう - Qiita

ルーティングをネスト構造へ変更

以下でAuthorの下にBookを入れる.
[config/routes.rb]

  resources :authors do
    resources :books
  end

ルーティングをネスト構造にすることで、以下のようにpathが自動的に割り当てられる.
f:id:Kurorera:20190525212130p:plain




Authorの設定

基本的に何もする必要なし。だけどBookの一覧表示へのリンクのみ作成しておく.

[app/views/authors/show.html.erb]

<%= link_to 'Book一覧', author_books_path(@author) %> 

Book側の設定

ルーティング(path)が変わっているのでそれに合わせて変更する必要あり.

indexアクション
[app/controller/books_controller.rb]
FROM

  # GET /books
  def index
    @books = Book.all
  end

TO

  # GET /authors/:author_id/books
  def index
    @author = Author.find(params[:author_id])
    @books = Author.find(params[:author_id]).books
  end

ビューを以下のようにパスを変更する.
[app/views/authors/index.html.erb]

  <td><%= link_to 'Show', author_book_path(@author,book) %></td>
  <td><%= link_to 'Edit', edit_author_book_path(@author,book) %></td>
  <td><%= link_to 'Destroy', author_book_path(@author,book), method: :delete, data: { confirm: 'Are you sure?' } %></td>

showアクション
コントローラ

  # GET  /authors/:author_id/books/1
  def show
    @author = Author.find(params[:author_id])
    @books = Author.find(params[:author_id]).books
  end

ビュー

<%= link_to 'Edit', edit_author_book_path(@author,@book) %> 
<%= link_to 'Back', author_books_path(@author) %>

共通処理の"_form.html.erb"の一行目の処理にauthorを追加する.
[app/view/books/_form.html.erb]

<%= form_with(model: [author,book], local: true) do |form| %>

newおよびcreateアクション
コントローラ
[app/controllers/books_controller.rb]

  # GET /authors/:author_id/books/new
  def new
    @author = Author.find(params[:author_id])
    @book = Author.find(params[:author_id]).books.new 
  end

  # POST /authors/:author_id/books
  def create
    @author = Author.find(params[:author_id])
    @book = Author.find(params[:author_id]).books.new(book_params)
    
    respond_to do |format|
      if @book.save
        format.html { redirect_to [@author,@book], notice: 'Book was successfully created.' }
        ...
      else
       ...
      end
    end
  end

ビュー
[app/views/books/new.html.erb]

<%= render 'form', author: @author, book: @book %>

<%= link_to 'Back', author_books_path(@author) %>


もう一度"_form.html.erb"に移動し、今度は16行目をの"form.text_field :author_id"とすることで初期値にauthor_idとしておく

<%= form.text_field :author_id, id: :book_author %>

editおよびupdateアクション
コントローラ

  # GET /authors/:author_id/books/1/edit
  def edit
    @author = Author.find(params[:author_id])
    @books = Author.find(params[:author_id]).books
  end

  # PATCH/PUT authors/:author_id/books/1
  def update
     @author = Author.find(params[:author_id])

      if @book.update(book_params)
        format.html { redirect_to [@author,@book], notice: 'Book was successfully updated.' }
         ...
      else
        ...
      end
    end
  end

ビュー

<%= render 'form', author: @author, book: @book %>

<%= link_to 'Edit', edit_author_book_path(@author,@book) %>
<%= link_to 'Back', author_books_path(@author) %>

updateはビューを持っていないので省略


Destroyアクション
コントローラ
[app/controllers/books_controller.rb]

  # DELETE authors/:author_id/books/1
  def destroy
       ...
      format.html { redirect_to author_books_url, notice: 'Book was successfully destroyed.' }
      ...
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_book
      @book = Author.find(params[:author_id]).books.find(params[:id]) 
    end
   ...
end

Destroyはビューを持っていないので省略

以上.すごく荒削りにしか開催していないのであまり参考にしないでください.
いずれわかりやすく書き直します.今はメモ程度.

Rails: "has_many", "blongs_to"でリレーショナルなテーブル関係を設定する

UserとPostのような1つに対して多くのアイテムを持つような時の設定方法.

参考サイト
Rails4で1対多のリレーションをモデルに実装する - Rails Webook
Active Record の関連付け (アソシエーション) - Rails ガイド
railsのbelongs_toとhas_manyとreferencesの使い方について整理する - 巨人の足元でたじlog



scaffoldで下準備

$ rails generate scaffold Author name:string
$ rails generate scaffold Book author:references published_at:datetime

"author:references"に関して、"author_id:integer"でもよいが、referencesとすることで勝手にRailsがidを作ってくれるみたい.


Author側の設定

f:id:Kurorera:20190518123808p:plain
Author側に:booksをたくさん持っていいよ(has_many)と設定する.
[app/models/user.rb]

class User < ApplicationRecord
    has_many :books, dependent: :destroy
end

Note: 1対多のリレーション時はhas_manyは複数形にする.


"dependent: :destroy"でUserが消されたときに一緒に削除されるよう設定.
他にもオプションがあるので参考サイト参照.

Book側の設定

f:id:Kurorera:20190518123727p:plain

Book側にauthorについていく(belongs_to)を設定する.
[app/models/post.rb]

class Post < ApplicationRecord
    belongs_to :author
end

デフォルトでは使用するキーはauthor_idが使われる.
キーを変更したい(外部キーを使いたい)場合はforeign_keyオプションで変更できる.
Note: 1対多のリレーション時はbelongs_toは単数形にする.


関連付けのメリット(意味)

"has_many","belongs_to"による関連付けにより以下のメソッドが使えるようになる.
f:id:Kurorera:20190518124224p:plain
f:id:Kurorera:20190518124942p:plain


Rails Consoleで試す.

$ rails console

いつも通りに新規作成およびテーブル登録

author1=Author.create(name:'Natsume')


book1を追加してauthor1とリンクさせて作成、テーブルへ追加

book1=author1.books.create(published_at:Time.parse("1905010100000000"))


以下実行結果."author_id"を設定していないのに自動的に設定されていることがわかる.

#<Book id: 3, author_id: 2, published_at: "1905-01-01 00:00:00", created_at: "2019-05-19 12:38:56", updated_at: "2019-05-19 12:38:56">

Ruby on Rails "Active Admin" + "CarrierWave"で画像アップロード

参考サイト
【Rails】PaperClip + active_adminで画像をアップロード - avosalmonのブログ
ruby on rails - Use Carrierwave with Active Admin - Stack Overflow


今回は以下で作成したActive Admin済みのBookモデルを使用します.
"$ rails generate migration AddImageToBook image:string"でカラムを追加して、"CarrierWave"のインストールと設定が状態とします.
詳細は以下の記事を参照
teki-com.hateblo.jp

追加

ActiveAdmin.register Book do
    permit_params :title, :company, :image
    
    form do |f|
      f.inputs "Books" do
        f.input :title
        f.input :company
        f.input :image, :as => :file
      end
      f.actions
    end
    
    show do |item_image|
      attributes_table do
        row :title
        row :company
        # show画面で画像を表示するためのタグを追加
        row :image do
          image_tag(book.image.url)
        end
      end
    end    
end

追加フォーム
f:id:Kurorera:20190514123429p:plain
確認フォーム
f:id:Kurorera:20190514123513p:plain

削除

特に気にすることなく管理画面の"delete"をすると画像も削除される.
f:id:Kurorera:20190514123853p:plain:w300

Ruby on Rails gem "Active Admin"で管理画面実装

参考サイト
Rails5 + ActiveAdmin 使い方 - Qiita
ActiveAdmin でのモデルの追加方法 (基本) - Qiita

Active Adminのインストール

GemfileにActive Admin本体およびそれに必要なdeviseを追加しインストールする.
[Gemfile]

# Active Admin
gem 'activeadmin', github: 'activeadmin'
gem 'inherited_resources', github: 'activeadmin/inherited_resources'

# 認証用
gem 'devise'
$ bundle install

インストーラの実行

$ rails generate active_admin:install 

管理者情報の変更(必要であれば)

インストーラの実行により"db/seeds.rb"に初期ユーザの情報が記載されているので必要に応じて編集する.

AdminUser.create!(email: 'admin@example.com', password: 'password', password_confirmation: 'password') if Rails.env.development?

マイグレーション

migrationの実行

$ rails db:migrate
$ rails db:seed

これでActive Adminの導入は完了.編集対象のモデルを追加する場合は以下を実行.

モデル(管理画面で表示する)の追加

モデル名はBookです.

$ rails generate scaffold Book title:string company:string

マイグレーションし、

$ rails db:migrate

リソースを作成.”app/admin/books.rb”が作成される.

$ rails generate active_admin:resource Book

"ルートアドレス/admin"にアクセスし、ログインすると”Books”が追加されている.
f:id:Kurorera:20190513033826p:plain:w300

最後に”app/admin/books.rb”にpermit_paramsを設定することで新規作成ができるようになる.

ActiveAdmin.register Book do
    permit_params :title, :company
end

*

Ruby on Rails gem "CarrierWave":画像削除実装

scaffoldで下準備

scaffoldを用いて生成.モデル名はPostとした.

$ rails g scaffold Post name:string image:string

Viewの変更(index)

createアクションで画像が設定されていないとnilが返ってくるため、nilでなければ画像を表示するように設定.

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Image</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @posts.each do |post| %>
      <tr>
        <td><%= post.name %></td>
        <td><% unless post.image.url.nil? %> <%= image_tag post.image.url %> <% end %></td>
        <td><%= link_to 'Show', post %></td>
        <td><%= link_to 'Edit', edit_post_path(post) %></td>
        <td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

Viewの変更(create)

画像登録フォームを作成するため[/app/views/posts/_form.html.erb]を以下のように変更.

  <div class="field">
    <%= form.label :image %>
    <p><%=form.label "画像をアップロード" %><br><%= form.file_field :image %></p>
  </div>

不格好だけどこんな感じ.

f:id:Kurorera:20190512045518p:plain:w200f:id:Kurorera:20190512045626p:plain

Destroy アクションに画像削除用コマンドを記入

以下サイトより、"remove_{カラム名}!"で削除できるとのことなのでdestroyアクションの初め2行に追加.
CarrierWaveでアップロードしているファイルを削除する - Qiita

  def destroy
    @post.remove_image!
    @post.save
    @post.destroy
    respond_to do |format|
      format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

削除完了.