20210117のRubyに関する記事は24件です。

ページネーション機能(kaminari)

はじめに

現在ポートフォリオ制作中の初学者です。
kaminariを導入してページネーション機能を実装したので備忘録です。

1. gemをインストール

Gemfile
gem 'kaminari'
ターミナル
% bundle install

2. コントローラーで定義

events_controller.rb
def index
  @events = Event.page(params[:page]).per(10)
end

pageとperいうメソッドがkaminariで定義されたメソッドです。
perメソッドの引数にどれだけのレコードが表示されたらページを増やすかを指定できます。

3. ビューファイルを編集

events/index.html.erb
<%= paginate @events %>

表示したいビューファイルに記述。

以上です!

ページネーションの見た目を変える

kaminariで表示させるページネーションはビューの中でcssを当てる事は出来ない。
ので以下方法。

ターミナル
% rails g kaminari:views default

app/viewsフォルダにkaminariを追加。
フォルダの中にページネーションの部分のhtmlが記述されているので、そこで変更する。

cssのフレームワークのデザインを適用させる場合

bootstrapなどのcssのフレームワークを使っている場合、表示やデザインが崩れる場合があるので
defaultの部分をそれぞれのフレームワークの名前に指定する。
bootstrap4を使っている場合は下記のコマンド。

ターミナル
% rails g kaminari:views bootstrap4

このコマンドを実行し、ビューファイルを作成すると何も編集しなくてもそれぞれのフレームワークのスタイルに最適化される。

kaminariを日本語化する

デフォルトで英語表記になっているため、日本語表記に変更するためには
config/localesフォルダにkaminari_ja.ymlというファイルを作成し、下記のようなコードを書く。

config/locales/kaminari_ja.yml
ja:
  views:
    pagination:
      first: "&laquo; 最初"
      last: "最後 &raquo;"
      previous: "&lsaquo; 前"
      next: " &rsaquo;"
      truncate: "..."

参考

https://pikawaka.com/rails/kaminari

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

汎用性◯『戻る』ボタン

はじめに

どんなページでも使える「戻るボタン」のコードを残しておこうと思い投稿します。

汎用的戻るボタン

  • Rails
  • erb拡張子
  • クラス名はお好みで
  • CSSでクラス名を指定すれば、スタイルを適用可能
<%= link_to '戻る', :back, class:"back-btn" %>

:backの部分が、戻る機能に起因しています。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Lambdaでコンテナデプロイする方法

はじめに

随分前になりますが、AWS Lambdaでコンテナデプロイがサポートされました。
AWS Lambda now supports container images as a packaging format

今回は、AWS Lambdaにコンテナのイメージをデプロイする方法について紹介します!

対象

  • AWS Lambdaの新機能について知りたい人
  • コンテナデプロイの流れを知りたい人

YouTube動画

動画で確認したい方は、こちらを利用ください!
*撮影は1ヶ月以上前のものですが、大きく変わったところはありません。
【YouTube動画】実践! Lambdaでコンテナデプロイをする方法!!
実践! Lambdaでコンテナデプロイをする方法!!

コンテナのデプロイ条件

Lambdaに、コンテナデプロイがサポートされましたが、コンテナなら何でも良いという訳ではありません。
AWSが提供しているLambda用のRuntime APIに準拠している必要があり、以下のいずれかの方法でコンテナを作る必要があります。

方法1: AWS提供のベースイメージを使う
方法2: Runtime APIが入っているイメージを使う

以下のサイトから使いたいランタイムを選択して、利用できます。
Runtime support for Lambda container images

具体例

今回はベースイメージを利用して、実際にLambdaにコンテナデプロイしてみます。
まず、簡単なNode.jsのサンプルを確認して、次に実践的なRubyのサンプルを見ていきます。

Node.jsのサンプル

簡単なサンプルを書くとこのようになります。

# ベースイメージの取得
FROM public.ecr.aws/lambda/nodejs:12

# Lambda関数を定義しているapp.jsをLambda実行時のルートディレクトリに置く
COPY app.js ${LAMBDA_TASK_ROOT}

# app.jsのhandler関数を実行
CMD [ "app.handler" ]

Rubyのサンプル

このサンプルはLambdaからMySQLに接続するためのLambda関数を作ります。
コンテナをサポートする前は、native extenstion関連で面倒な手順が必要でしたが、コンテナをサポートしたことで簡単に使えるようになりました。

FROM amazon/aws-lambda-ruby:2.7

WORKDIR ${LAMBDA_TASK_ROOT}

# MySQL関連で依存しているものをインストール
RUN yum install -y mysql-devel gcc-c++ make

COPY . ${LAMBDA_TASK_ROOT}

RUN bundle config --global silence_root_warning 1
RUN bundle config set path 'vendor/bundle'
RUN bundle install

CMD ["app.App::Handler.process"]

ローカルでLambdaを動かす

コンテナ化したことで、ローカルで実際に試すことができます。

9000番ポートを開放して試したい場合は次のようにします。

docker run -p 9000:8080 <image name>

そして、以下のようにPOSTすることで、実際に確認できます。
ここでの、/2015-03-31/functions/function/invocations"は固定です。

curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" \
-d '{"payload":"hello world!"}'

デプロイ

まずはコンテナイメージをAmazon ECRにデプロイする必要があります。
今回は割愛します。以下が詳しいです。
Docker イメージをプッシュする

Lambdaの関数の作成方法を確認すると、コンテナイメージという項目ができているので、そちらを選択して使います。
_2020-12-07_20.20.44.png

まとめ

今回はAWS Lambdaにコンテナをデプロイする方法について解説しました。
この記事を通してざっくり理解していただくと、自分で設定する時にスムーズだと思います。

また、AWS Lambdaでコンテナを使った場合は、最初の起動で2 ~ 5秒程度かかってしまいますが、それ以降はスムーズに起動します。
AWS Lambdaの利用の幅が広がる新機能なので、ぜひ遊んでみてください!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Ruby]文字列で使えるメソッド

文字列の置換

  • 文字列.sub(/変換した文字/,"置き換えたい文字列)・・・一番最初の文字のみ変換
irb(main):026:0> str
=> "123123123"
irb(main):027:0> str.sub(/12/,"ab")
=> "ab3123123"
irb(main):028:0> str
=> "123123123"

12と言う文字をabと変換したらab3123123と置換された
ただしインスタンス自体は置換されていない

  • 文字列.gsub(/変換した文字/,"置き換えたい文字列)・・・対応したすべての文字を変換 gはグローバルの意味
irb(main):029:0> str.gsub(/12/,"ab")
=> "ab3ab3ab3"

これも同様にインスタンス自体は置換されない

  • 文字列.sub!(/変換した文字/,"置き換えたい文字列)・・・元のインスタンス自体の一番最初の文字のみ変えてしまう

!は破壊的メソッド・・・インスタンス自体を変換してしまう

irb(main):030:0> str.sub!(/12/,"ab")
=> "ab3123123"
irb(main):031:0> str
=> "ab3123123"
  • 文字列.gsub!(/変換した文字/,"置き換えたい文字列)・・・元の変数自体をすべての文字を変えてしまう
irb(main):034:0> str = "123123123"
=> "123123123"
irb(main):035:0> str.gsub!(/12/,"ab")
=> "ab3ab3ab3"
irb(main):036:0> str
=> "ab3ab3ab3"

文字列の検索

  • 文字列.index("検索したい文字列”)・・・検索してどこに検索したい文字列があるか教えてくれる
irb(main):038:0> "12345".index("2")
=> 1

もちろん変数に格納された文字列も検索できる

irb(main):041:0> str = "abcde"
=> "abcde"
irb(main):042:0> str.index("c")
=> 2

これを見て、”12345”で”2”を検索しているのに”1”っておかしくないと思いましたよね?
格納された要素は添字といった番号を割り振られます
添字は0からスタートするので”12345”と言う文字列は”1”から番号が割り振られるのではなく、”0”から割り振られるます
だから”2”の検索結果が”1”となった訳です

文字列の削除

  • 文字列.delete(”削除したい文字列”)・・・指定された文字列の削除
  • 文字列.delete!(”削除したい文字列”)・・・(インスタンスからも)指定した文字列の削除
irb(main):044:0> str.delete("cd")
=> "abe"
irb(main):045:0> str
=> "abcde"

当然!をつけると破壊的メソッドになるのでインスタンスも変化(削除)されてしまう

  • 文字列.chop・・・文字列の行末を削除できる
irb(main):049:0> str.chop
=> "abcd"

これも!を付けると破壊的メソッドになる

  • 文字列.chomp・・・改行コードも削除できる

例えばchomoなしでgetsを利用して文字列入力すると

irb(main):054:0> gets.to_s
私の名前は太郎
=> "私の名前は太郎\n"

と\nと改行コードが組み込まれてします

それをchompを利用すると

irb(main):053:0> gets.to_s.chomp
私の名前はたろう
=> "私の名前はたろう"

\nが組み込まれない

文字の分割して配列を作成

文字列.split

irb(main):055:0> "aa bb cc".split
=> ["aa", "bb", "cc"]

空白を入れると分割されて配列が作成される
余談ですが、railsでタグ機能を作る時にgemなしの場合splitを使用して複数作ります(経験談)
これは文字を指定して分割する事も可能で、例えば","なら

文字列.split(",")でカンマを指定してして分割出来ます

例:
irb(main):058:0> "aa,bb,cc".split(",")
=> ["aa", "bb", "cc"]

逆に作った配列を文字列に戻す方法は
配列.joinを使います

例:whatの中に先ほどの入れる["aa", "bb", "cc"]が格納されております
irb(main):059:0> what.join
=> "aabbcc"

配列.join(" ")と指定してあげると

irb(main):061:0> what.join(" ")
=> "aa bb cc"

と分割された状態で文字列に戻します

文字列の変換

文字列.upcase・・・大文字に変換
文字列.downcase・・・小文字に変換

irb(main):063:0> length = "aaa"
=> "aaa"
irb(main):064:0> length.upcase
=> "AAA"
irb(main):065:0> length.upcase!
=> "AAA"
irb(main):066:0> length
=> "AAA"
irb(main):067:0> length.downcase
=> "aaa"
irb(main):068:0> length.downcase!
=> "aaa"
irb(main):069:0> length
=> "aaa"

文字列.reverse・・・文字列を左右反転

irb(main):072:0> length = "abc"
=> "abc"
irb(main):073:0> length.reverse
=> "cba"

文字列.slice(範囲)・・・文字列を指定した範囲を切り取ってくれる

irb(main):076:0> length = "abcdef"
=> "abcdef"
irb(main):077:0> length.slice(2..4)
=> "cde"

2〜4までの範囲の文字列cdeを切り取ってくれました
このslice(2..4)の..は範囲をしているする時に使います

最後

ノートにあったものを片っ端からまとめてみました
もしかしたら解釈が間違えているかもしれませんのでもしよかったらご指摘お願いします

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】SNSアプリにおけるリツイート機能の実装

現在就活用のポートフォリオとして、自分の好きな物をレビュー付きで共有できるRevoriteというSNSアプリを作成しています。
基本的な投稿機能やいいね機能などはググるとたくさんヒットしますが、リツイート機能に関する記事が少ないように感じたので、備忘録も兼ねてどなたかの参考になればと思い記事にしました。

前提

ユーザを管理するuserモデル、投稿(ツイート)を管理するpostモデル、フォロー・フォロワーの関係を管理するrelationshipモデルはそれぞれ作成済み

モデルの作成

リポスト(当アプリではツイートではなく投稿(post)という言葉で統一しているため、以降リツイートではなくリポストと呼んでいます)を管理するrepostモデルを作成します。

$ rails g model repost
YYYYMMDDHHMMSS_create_reposts.rb
class CreateReposts < ActiveRecord::Migration[5.2]
  def change
    create_table :reposts do |t|
      t.references :user, foreign_key: true
      t.references :post, foreign_key: true
      t.timestamps
    end
  end
end
$ rails db:migrate

repostsテーブルを作成。誰がどの投稿をリポストしたか、を管理します。

次にアソシエーションです。ユーザは複数投稿をリポストできるし、一つの投稿は複数ユーザにリポストされうるため、repostsテーブルはユーザと投稿の多対多の中間テーブルという位置付けになります。

user.rb
has_many :reposts, dependent: :destroy
post.rb
has_many :reposts, dependent: :destroy
repost.rb
belongs_to :user
belongs_to :post

コントローラの作成

次にユーザが投稿をリポストできるように、コントローラを作成します。リポストした投稿のリポストボタンを再度押すことで取り消すことも可能です。

$ rails g controller reposts
reposts_controller.rb
class RepostsController < ApplicationController
  before_action :set_post

  def create  # リポストボタンを押下すると、押したユーザと押した投稿のIDよりrepostsテーブルに登録する
    if Repost.find_by(user_id: current_user.id, post_id: @post.id)
      redirect_to root_path, alert: '既にリポスト済みです'
    else
      @repost = Repost.create(user_id: current_user.id, post_id: @post.id)
    end
  end

  def destroy  # 既にリポストした投稿のリポストボタンを再度押下すると、リポストを取り消す(=テーブルからデータを削除する)
    @repost = current_user.reposts.find_by(post_id: @post.id)
    if @repost.present?
      @repost.destroy
    else
      redirect_to root_path, alert: '既にリポストを取り消し済みです'
    end
  end

  private
  def set_post  # リポストボタンを押した投稿を特定する
    @post = Post.find(params[:post_id])
    if @post.nil?
      redirect_to root_path, alert: '該当の投稿が見つかりません'
    end
  end
end

ここで併せてルートも編集しておきます。

routes.rb
resources :posts, only: [:index, :new, :create, :destroy] do
  resources :reposts, only: [:create, :destroy]
end

リポストボタンの組み込み

ビューにリポストボタンを組み込みます。
各投稿にボタンを表示する必要があるため、部分テンプレートで実装しています。

_repost.html.haml
- if user_signed_in?
  - unless post.user.id == current_user.id  # 自身の投稿はリポストできない
    - if current_user.reposted?(post.id)
      = link_to "/posts/#{post.id}/reposts/#{post.reposts.ids}", method: :delete, title: "リポストを取り消す", remote: true do
        %i.fas.fa-retweet.post-action__repost--reposted
        = post.reposts.length
    - else
      = link_to "/posts/#{post.id}/reposts", method: :post, title: "リポストする", data: {confirm: "この投稿をリポストしますか?"}, remote: true do
        %i.fas.fa-retweet
      = post.reposts.length
  - else
    %i.fas.fa-retweet.nonactive
    = post.reposts.length
- else
  %i.fas.fa-retweet.nonactive
  = post.reposts.length

reposted?(post.id)メソッドは以下で定義しています。ユーザがそのポストをリポスト済みかどうかの判定用です。

user.rb
def reposted?(post_id)
    self.reposts.where(post_id: post_id).exists?
end

これで、ユーザが任意の投稿のリポストボタンを押すと、その情報がrepostsテーブルに登録されるようになりました。

リポストを含んだユーザの投稿一覧を表示

次に、ユーザの投稿一覧を表示するページで、そのユーザの投稿だけでなくリポストもいっしょに表示できるようにします。
通常、ユーザの投稿だけであればuser.postsで取得できますが、リポストも併せてとなると途端に難易度が上がります。(ここでかなり苦労しました、、)

ユーザ自身の投稿及びリポストした投稿を取得

リポストを同時に取得できるように、posts_with_repostsというメソッドを定義していきます。

user.rb
def posts_with_reposts
  relation = Post.joins("LEFT OUTER JOIN reposts ON posts.id = reposts.post_id AND reposts.user_id = #{self.id}")
                 .select("posts.*, reposts.user_id AS repost_user_id, (SELECT name FROM users WHERE id = repost_user_id) AS repost_user_name")
  relation.where(user_id: self.id)
          .or(relation.where("reposts.user_id = ?", self.id))
          .with_attached_images
          .preload(:user, :review, :comments, :likes, :reposts)
          .order(Arel.sql("CASE WHEN reposts.created_at IS NULL THEN posts.created_at ELSE reposts.created_at END"))
end

順番に上から見ていきましょう。
いきなりrelation = Post.・・・と出てきているのは、後に登場するorメソッドで繰り返し記述が必要になるため、変数化しています。
その内容ですが、postsに対して左外部結合でrepostsを取得しています。一つの投稿には複数ユーザがリポストすることがあるため、結合条件のON句の中で自身のリポストのみで絞っています。left_joinsメソッドだとON句を自由に設定できないようなので、joinsメソッドでベタ書きしています。
単純にeager_loadでJOINしてwhereで自身のリポストのみを絞り込むやり方も考えたのですが、投稿やリポストが増えるほど性能面への影響が跳ね上がるため、記述は少し煩雑ですが先に絞り込んだ形のrepostをJOINすることで取得する、という形にしています。

その次のselectメソッドですが、postsだけでなくrepostsの情報も取得したい(のちにビューで利用する)ので指定しています。
ここまでが取得対象のテーブル、取得項目を表しています。次からは取得条件です。

relation.where(user_id: self.id).or(relation.・・・ですが、これはユーザ自身の投稿、またはリポストしたユーザが自身である投稿を取得する、という意味になります。
.with_attached_images.preload(・・・でN+1問題を回避しつつ投稿に付随するアソシエーションを取得します。ここではpostsreposts以外はデータ絞り込み等では使わない(ビューの表示でのみ使う)ため、性能を考慮してeager_loadではなくpreloadを採用しています。

最後の.order(・・・、取得順ですが、基本は投稿日時順です。ただし、リポストした投稿は投稿日時ではなくリポストした日時で順序判定をする、という指定をしています。自身の投稿であればJOINしたrepostsの各項目はNULLであることから判定してソート項目を使い分けています。
orderメソッド内で条件文を使おうと思うとベタ書きにせざるを得ないのですが、そうすると Dangerous query method ... みたいなエラーが発生します。
これはRails5.2からの機能で、order句の中でSQLをベタ書きするとSQLインジェクションの危険性がありますよ!という警告をしてくれるものだそうです。Arel.sql(...)で囲えば警告は出なくなるので、危険性が無いことを確認した上で使ってね、という意味合いですね。(参考記事:Arel.sqlを付けるだけじゃダメ!? Railsで"Dangerous query method …”の警告が出たときの対応方法
今回はタイムスタンプ項目であるcreated_atを順序判定の項目として使うだけで、問題無いことは明白なのでArel.sql(...)で囲んで警告を回避しています。

コントローラーに記述、及びビューへの表示

users_controller.rb
class UsersController < ApplicationController
  before_action :set_user

  def show
    @posts = @user.posts_with_reposts
  end

  private
  def set_user
    @user = User.find(params[:id])
  end
end
_posts.html.haml
- posts.each_with_index.reverse_each do |post, i|
  %li.post
    - if post.has_attribute?(:repost_user_id)  # リポストを取得しない投稿一覧ページ(お気に入り一覧など)でも同じ部分テンプレートを利用しているため、この判定を入れている
      - if post.repost_user_id.present?
        .post-repost
          %i.fas.fa-retweet
          = link_to post.repost_user_name, "/users/#{post.repost_user_id}", "data-turbolinks": false
          さんがリポスト
    .post-container
      .post-left
        = link_to user_path(post.user.id), "data-turbolinks": false do
          - if post.user.image.attached?
            = image_tag(post.user.image, alt: 'デフォルトアイコン')
          - else
            = image_tag('sample/default_icon.png', alt: 'デフォルトアイコン')
      .post-right
        = render partial: "posts/post", locals: {post: post}
        = render partial: "posts/comment", locals: {post: post}
  - if i != 0
    %hr

こんな感じで、ユーザの投稿及びリポストした投稿の一覧を表示できました。
参考画像

リポストを含んだタイムラインの表示

タイムライン(ユーザがフォローしている人(=フォロイー)の投稿一覧)には、ユーザの投稿一覧ページと同様に、フォロイーの投稿だけでなく彼らのリポストも表示する必要があります。
ただ、ユーザの投稿一覧ページとは違う点として、複数の異なるフォロイーが同じ投稿をリポストしている場合、重複して表示をしないようにするといった考慮が必要になってきます。
この点を踏まえた上で実装したメソッドfollowings_posts_with_repostsが以下です。

user.rb
def followings_posts_with_reposts
  relation = Post.joins("LEFT OUTER JOIN reposts ON posts.id = reposts.post_id AND (reposts.user_id = #{self.id} OR reposts.user_id IN (SELECT follow_id FROM relationships WHERE user_id = #{self.id}))")
                 .select("posts.*, reposts.user_id AS repost_user_id, (SELECT name FROM users WHERE id = repost_user_id) AS repost_user_name")
  relation.where(user_id: self.followings_with_userself.pluck(:id))
          .or(relation.where(id: Repost.where(user_id: self.followings_with_userself.pluck(:id)).distinct.pluck(:post_id)))
          .where("NOT EXISTS(SELECT 1 FROM reposts sub WHERE reposts.post_id = sub.post_id AND reposts.created_at < sub.created_at)")
          .with_attached_images
          .preload(:user, :review, :comments, :likes, :reposts)
          .order(Arel.sql("CASE WHEN reposts.created_at IS NULL THEN posts.created_at ELSE reposts.created_at END"))
end

基本的には前述したposts_with_repostsメソッドと構成は近いです。異なる点を順に挙げていきます。

 
relation = Post.joins(
posts_with_repostsメソッドでは自身のリポストのみに絞ったrepostsをJOINしていましたが、ここでは自身またはフォロイーのリポストのみに絞り込んでいます。
本当はuser_id IN (#{self.followings_with_userself.pluck(:id)})みたいに実装したかったのですが、この記述の場合コンパイルされるとIN句の中が([1,2,3])みたいになって上手く取得できないため、少し冗長ですがrelationshipsからフォロイーのIDを取得して条件に指定しています。
ベタ書きではない通常のwhereメソッド等でpluckを使う分にはうまくいくのですが…ここは上手なやり方があれば多少リファクタリングできそうです。

 
relation.where(user_id: self.followings_with_userself.pluck(:id))
ユーザまたはフォロイーの投稿一覧を取得しています。一応ですがfollowings_with_userselfはあらかじめ以下のように定義しています。

user.rb
def followings_with_userself
  User.where(id: self.followings.pluck(:id)).or(User.where(id: self.id))
end

 
.or(relation.where(・・・
.where("NOT EXISTS(・・・
中身を見る前に文の構成がややこしいので前置きすると、一つ前のwhere文をA、当説明のor文をB、where文をCとするとA OR (B AND C)という構成になっています。
取得したいデータの条件は以下の通りです。
(ユーザとフォロイー自身の投稿) または ((ユーザとフォロイーがリポストした投稿) かつ (重複している中で一番リポスト日時が新しいもの))

repostsはLEFT JOINで取得しているため、一つの投稿に対し複数のフォロイーがリポストした場合、同じ投稿が複数レコード取得されてしまいます。そのため一つの投稿に対し複数のrepostsレコードがJOINされる場合、その中でもrepostscreated_atが一番新しいレコードのみを取得する、という条件を入れています。これはNOT EXISTSとサブクエリを利用し、「自身よりも新しいレコードが無い」という条件にすることで実現できます。

コントローラーに記述、及びビューへの表示

posts_controller.rb
def index
  if user_signed_in?
    @user = User.find(current_user.id)
    @posts = @user.followings_posts_with_reposts
  else
    # 未ログインの場合、フォローやタイムラインといった概念が無いため、リポストは表示せず投稿のみを表示
    @posts = Post.with_attached_images.preload(:user, :review, :comments, :likes)
  end
end

ビューは先述と同じため(部分テンプレートで共通)割愛します。

こんな感じでタイムラインを表示できました。
参考画像

最後に

アソシエーションを組んでいるテーブルを取得する際はとりあえずN+1問題回避のためにincludesだ!くらいの知識しか無かったのですが、このリツイート機能の実装に伴い eager_loading と lazy loading の違い、join / preload / eager_load / includes の違いをしっかり理解する良い機会となりました。
ポートフォリオ作成においてはポピュラーなSNSアプリですが、リツイート機能は他の機能よりは比較的難易度は高めだと思います。記事が少ないということは実装している方も少ないのかな?個人的にはとても勉強になったので、SNSアプリを開発している方は是非実装してみてはいかがでしょうか。

以下、データ取得の考えた方として参考にさせていただいた記事です。
ActiveRecordのincludesは使わずにpreloadとeager_loadを使い分ける理由
ActiveRecordのjoinsとpreloadとincludesとeager_loadの違い

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

seeds.rbなどでActiveStorageを使って大量の画像をアップロードする際に発生する SQLite3::BusyException の対処法

発生する問題

Railsのrails db:seedを実行すると、以下のようなエラーが起きる場合がある。

$ rails db:seed
rails aborted!
ActiveRecord::StatementInvalid: SQLite3::BusyException: database is locked
/path-to-your-app/db/seeds.rb:69:in `<main>'

エラーが発生するコード例

エラーが発生した周辺のコードは次のようになっている。

# ...

User.destroy_all

100.times do |n|
  user = User.create!(
    email: "sample-#{n}@example.com",
    password: 'password',
    name: Faker::Name.name
  )
  image_url = Faker::Avatar.image(slug: user.email, size: '150x150')
  # ActiveStorageを使ってavatarを設定
  user.avatar.attach(io: URI.parse(image_url).open, filename: 'avatar.png')
end

# ...

加えて、このアプリケーションではSQLite3を使っている。

default: &default
  adapter: sqlite3
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000

development:
  <<: *default
  database: db/development.sqlite3

エラーが発生する原因

このエラーは以下の2つの要因で引き起こされる。

  • ActiveStorageを使っているため、画像のアップロードや削除が非同期で行われる
  • SQLite3は並行処理に弱い(参考

User.destroy_allをしたときは既存のデータに対して画像の削除処理が非同期で実行される。既存のデータが大量にあると、データベースに対して読み込みや書き込みのクエリが並行して発行される。

user.avatar.attachも同様に非同期で画像のアップロード処理が行われる。上のコード例では100件のユーザーデータを作成しようとしたため、やはりデータベースに対して読み込みや書き込みのクエリが並行して発行される。

SQLiter3が並行処理に耐えきれなくなると、SQLite3::BusyExceptionが発生する。

エラー回避策

SQLite3の性能上の制約を考慮し、画像の削除処理やアップロード処理を同期的に行うようにする。具体的には以下の2行をconfig/seeds.rbに追加する。

+ActiveStorage::AnalyzeJob.queue_adapter = :inline
+ActiveStorage::PurgeJob.queue_adapter = :inline

 User.destroy_all

 100.times do |n|
   user = User.create!(
     email: "sample-#{n}@example.com",
     password: 'password',
     name: Faker::Name.name
   )
   image_url = Faker::Avatar.image(slug: user.email, size: '150x150')
   user.avatar.attach(io: URI.parse(image_url).open, filename: 'avatar.png')
 end

ActiveStorage::AnalyzeJobはアップロード時に、ActiveStorage::PurgeJobは削除時にそれぞれ利用されるActiveJobのクラスである。
このqueue_adapter:inlineに変更することで、画像のアップロードや削除を同期的に実行できる。

参考 https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters/InlineAdapter.html

動作確認環境

  • Rails 6.1.0
  • Ruby 3.0.0
  • SQLite3 3.32.3
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsで簡単にサイトの雛形を作る

サマリ

サイトをたくさん作れるようになりたいけど、どうやろうか?という疑問が浮かんだ。
そこで、いろんなチュートリアルサイトを見たけど、Railsでつかうscaffoldという機能が便利そうだったから、その実施をやってみる。

プロジェクトの立ち上げ

Ruby と Railsの導入

まずは、rubyとRailsをPCにセットアップする。
以下の記事を参考に実施した。(Mac)

【完全版】MacでRails環境構築する手順の全て

上記の記事を参考にして一通りのインストールを行う。

振り返っての注意点だが、なるべく過去1年間に投稿された記事をなるべく参考にしたほうがいいと思う。
それ以上前だと、os自体のバージョンアップをまたいだりとうまく動かない可能性が出てくる。

Railsプロジェクトの実行

$ rails new scaffold_sample
$ cd scaffold_sample
$ rails generate scaffold user name:string age:integer

こんな感じで入力すると、ユーザーモデルを備えたviewやcontrollerが一通りできる。

画面の操作も可能なので、何をやっていけばいいか?は結構わかりやすいかも。

次からは、こんなサイトを作れるように色々やっていこうかな。
ハロワ求人検索
ハロワまとめサイト
ハローワーク検索サイト

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】gem active_decoratorでコードを綺麗にまとめる

背景

・カラムの合計値や平均値といった計算をviewに書いていると、ごちゃごちゃしてきて読みにくくなってきたため。
・viewに書くのか、controllerに書くのか問題の解決のため

導入

まずはgemfileに追記します。

gem 'active_decorator'

bundle installします。

$ bundle install

decoratorファイルの生成

次に、decoratorファイルを作ります。
今回はscoreというモデルに関するものです。
scoreの部分は好きな名前にして下さい。

$ rails g decorator score

そうすると、このようなファイルを生成してくれます。
app/decorators/score_decorator.rb

今回はゴルフのスコアだったので、18Hの合計を計算させます。

module ScoreDecorator
  def total_score
    format('%+d', hole1_score.to_i + 
                  hole2_score.to_i + 
                  hole3_score.to_i +
              ・
              ・
              ・
                  hole18_score.to_i)
  end
end

viewで出力

これでviewがすっきりしました!

  <% @scores.each do |score| %>
        <%= score.total_score %>
  <% end %>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】gem Decoratorでコードを綺麗にまとめる

背景

・カラムの合計値や平均値といった計算をviewに書いていると、ごちゃごちゃしてきて読みにくくなってきたため。
・viewに書くのか、controllerに書くのか問題の解決のため

導入

まずはgemfileに追記します。

gem 'active_decorator'

bundle installします。

$ bundle install

decoratorファイルの生成

次に、decoratorファイルを作ります。
今回はscoreというモデルに関するものです。
scoreの部分は好きな名前にして下さい。

$ rails g decorator score

そうすると、このようなファイルを生成してくれます。
app/decorators/score_decorator.rb

今回はゴルフのスコアだったので、18Hの合計を計算させます。

module ScoreDecorator
  def total_score
    format('%+d', hole1_score.to_i + 
                  hole2_score.to_i + 
                  hole3_score.to_i +
              ・
              ・
              ・
                  hole18_score.to_i)
  end
end

viewで出力

これでviewがすっきりしました!

  <% @scores.each do |score| %>
        <%= score.total_score %>
  <% end %>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

0から Ruby on Rails の環境構築【macOS】 (Homebrew のインストールから Rails のインストールまで)

【macOS】 Ruby on Rails 6.1 環境構築 (Ruby 3.0)

本記事はRuby on Railsの環境構築を初心者の方でも迷わずできるように解説した記事です。

Ruby on Railsは、広範囲にわたる開発で使用されています。日本のスタートアップでも採用されていることが多く、食べログやnote、会計ソフトのfreeeなどもRuby on Railsによって開発されています。

そんなRuby on Railsですが、2019年8月にバージョン 6.0.0 がリリース、2020年12月にはバージョン 6.1.0 がリリースされました。また、Ruby自体も2020年12月にバージョン3.0にメジャーアップデートされ新しい機能が追加されています。

本記事では、Ruby 3.0Ruby on Rails 6.1.1 の環境構築方法を説明していきます。

環境

  • macOS (Windowsには対応していません)
  • Terminalはbashを使用しています
    • zsh の場合は一部動作しない箇所があります

Homebrewをインストール

ソフトウェアの導入を簡単にするため、macOS用のパッケージ管理システムであるHomebrewをインストールします。

次のリンク先からHomebrewをインストールします。

Homebrew

リンク先にアクセスすると次のページが表示されます。

image

「インストール」の見出しの下にあるスクリプトの行をmacOSのターミナルにコピー&ペーストします。

ターミナルで実行するとHomebrewのインストールが開始されます。

インストールには数分~10分ほどかかります。途中で何度かパスワードを要求されるので、使用しているパソコンのパスワードを入力してください。

Homebrewのインストール後に、無事にインストールされたかどうかを確認します。

インストール後の確認は、ターミナルを起動して次のコマンドを入力します。

brew -v

入力をしたらenterキーを押して、コマンドを実行します。

コマンドが実行されると、次のような画面になります。

Homebrew 2.7.1
Homebrew/homebrew-core (git revision 9adfd; last commit 2021-01-05)
Homebrew/homebrew-cask (git revision 3d3c93; last commit 2021-01-05)

「Homebrew 2.7.1」とバージョンが表示され、Homebrewがインストールされたことが確認できました。

(執筆時は「2.7.1」と表示されましたが、「2.7.2」などと表示されると最新版がインストールされたことになります)

rbenvのインストール

次に、Rubyのバージョンを簡単に切り替えられるrbenvをインストールします。

それでは、ターミナルで次のコマンドを入力して実行してください。

brew install rbenv

コマンドを実行後に、実際にrbenvがインストールされているかを確認します。

次のコマンドを入力して、インストールしたrbenvのバージョンを確認します。

rbenv --version

コマンドを実行すると、次のようにバージョン情報が表示されます。

rbenv --version
rbenv 1.1.2

この表示では「rbenv 1.1.2」とバージョン情報が表示されています。

rbenvがインストールされたことを確認できました。

rbenvにPATHを通す

rbenvコマンドを利用するために、rbenvにPATHを通します

「PATHを通す」とは、コマンドの実行ファイルの場所を確認するために指定することです。

参考:PATHを通すとは?(Mac OS X)

rbenvコマンドのPATHを通すために、次の3つのコマンドを用意しました。

echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
echo 'if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi' >> ~/.bash_profile
source ~/.bash_profile

これらのコマンドを1行ずつ入力して、実行します。

まずは最初のコマンドです。

スクリプトを.bash_profileに追加します。

echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile

>> ~/.bash_profileでスクリプトを.bash_profileに追加しました。

次に、2番めのコマンドを入力して実行します。

echo 'if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi' >> ~/.bash_profile

このコマンドを追加することで、ターミナル起動時にrbenvを自動的に起動させます。

最後に、sourceというコマンドを使って追加した内容を反映します。

source ~/.bash_profile

.bash_profileに追加した内容を反映できました。

これでrbenvコマンドを利用するのに必要なPATHが通りました。

Rubyの環境構築

次にRubyをインストールします。

Rubyをインストールする前に、インストールできるRubyのバージョンを確認します。

先ほどインストールしたrbenvを使って次のコマンドを入力してください。

rbenv install -l

コマンドを実行すると、最新の安定版のバージョンが一覧で表示されます。

rbenv install -l
2.5.8
2.6.6
2.7.2
3.0.0
jruby-9.2.13.0
maglev-1.0.0
mruby-2.1.2
rbx-5.0
truffleruby-20.2.0
truffleruby+graalvm-20.2.0

Only latest stable releases for each Ruby implementation are shown.
Use 'rbenv install --list-all' to show all local versions.

※ インストール可能なrubyのバージョンを全て表示するには、上記の実行結果にあるようにrbenv install -lというコマンドを実行します

バージョン番号を見ると、執筆時点(2021年1月)の安定版の最新バージョンは「3.0.0」なので、3.0.0をインストールします。

参考:Ruby ダウンロード

もし最新バージョンが表示されない場合は、rbenvとruby​​-buildを最新版にする必要があります。

参考:rbenv Upgrading with Homebrew

それでは、次のコマンドを入力してRuby 3.0.0 をインストールします。

rbenv install 3.0.0

コマンドを実行するとインストールを開始します。インストール完了まで数分間かかることがあります。

これでRubyがインストールされました。

ローカルで使うRubyのバージョンを指定

さらにローカルで使うRubyのバージョンを指定するために、以下のコマンドを実行します。

rbenv local 3.0.0

これでローカルでRubyの3.0.0のバージョンが使用されます。

このようにlocalを使うと、プロジェクトごとにRubyのバージョンを指定できます。

PC(サーバー)内で同じバージョンを共通して使う場合は、localではなくglobalを使います。

次に、Rubyのバージョン情報を確認します。次のコマンドを入力します。

ruby -v

コマンドを実行すると、次のようにバージョンが表示されます。

ruby -v
ruby 3.0.0p137 (2020-10-01 revision 5445e04352) [x86_64-darwin19]

指定した「3.0.0」と表示されました。これで指定したRubyのバージョンが確認できました。

Bundlerをインストール

Rubyをインストールしたら、次にBundlerをインストールします。

RubyではGemというライブラリを使いパッケージを管理しています。

Gemコマンドで簡単にインストールやアンインストールができますが、複数のGemを使うとGem同士で依存関係が生まれ、バージョン違いによる不具合が出てきます。

そこで、BundlerでGemのそれぞれのバージョンを正確に追跡し管理して、Rubyプロジェクトに一貫した環境を提供します。

参考:
- Bundler
- RubyGems

それではBundlerをインストールしましょう。以下のコマンドを入力します。

gem install bundler

コマンドを実行するとインストールが始まります。

インストールされたBlundlerのバージョンを確認しましょう。

次のコマンドを入力します。

bundler -v

コマンドの実行後、次のように表示されます。

bundler -v
Bundler version 2.2.3

「version 2.2.3」とバージョン情報が表示されました。

これでBlundlerがインストール済みであることを確認できました。

yarnをインストール

次にyarnをインストールします。

yarnはJavaScriptのライブラリの利用に必要なパッケージマネージャです。

yarnと互換性のあるnpmというパッケージマネージャもあります。しかし、Rails6ではWebpackerが標準になったことにより、yarnが必要です。

それでは、yarnのインストールを行いましょう。

次のコマンドを入力します。

brew install yarn

Homebrewのコマンドを実行すると、yarnがインストールされます。

yarnが実際にインストールされたかを確認するために、次のコマンドを入力します。

yarn -v

コマンドを実行すると、次のように表示されます。

yarn -v
1.22.10

ここでは「1.22.10」と表示されました。バージョン情報が表示されていれば、yarnがインストールされたことが確認できます。

Ruby on Railsのインストール

いよいよ、Railsをインストールします。

Railsのインストール時に「-v バージョン番号」とバージョンを指定してインストールできます。

今回はバージョン「6.1.1」をインストールします。

参考:railsの全バージョン履歴

次のコマンドを入力します。

gem install rails -v 6.1.1

コマンドを実行すると、インストールを開始します。インストールの完了までに数分かかることがあります。

Railsのバージョンを確認

Railsをインストールしたら、Railsのバージョンを確認するために次のコマンドを入力します。

rails -v

コマンドを実行すると、次の画面が表示されます。

rails -v
Rails 6.1.1

Rails 6.1.1」と表示されました。

これで無事にRuby on Railsのインストールが完了しました。

※ 本記事はTechpitの教材を一部修正したものです。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rubyのビルド時のオプション知りたかったら `RbConfig::CONFIG["configure_args"]` をみる

tl;dr

  • crubyのビルド時のオプション知りたかったら RbConfig::CONFIG["configure_args"] をみる。

環境

$ uname -mrv
4.15.0-124-generic #127-Ubuntu SMP Fri Nov 6 10:54:43 UTC 2020 x86_64
$ cat /etc/issue
Ubuntu 18.04.5 LTS \n \l

$ rbenv --version
rbenv 1.1.2-34-g0843745
$ ruby -v
ruby 2.5.8p224 (2020-03-31 revision 67882) [x86_64-linux]

本題

rbenvで入れたバイナリでdpkg-shlibdepsかけたらなんか言われた。

$ pwd
/home/kubo39/.anyenv/envs/rbenv/versions/2.5.8/bin
$ mkdir debian;touch debian/control
$ dpkg-shlibdeps -v -v ruby
dpkg-shlibdeps: debug: >> Scanning ruby (for Depends field)
dpkg-shlibdeps: debug: Library libruby.so.2.5 found in /home/kubo39/.anyenv/envs/rbenv/versions/2.5.8/lib/libruby.so.2.5
dpkg-shlibdeps: debug: Skipping lib /lib/i386-linux-gnu/libc.so.6, libabi=0x0101000300000000 != objabi=0x0201003e00000000
dpkg-shlibdeps: debug: Skipping lib /lib32/libc.so.6, libabi=0x0101000300000000 != objabi=0x0201003e00000000
dpkg-shlibdeps: debug: Skipping lib /libx32/libc.so.6, libabi=0x0101003e00000000 != objabi=0x0201003e00000000
dpkg-shlibdeps: debug: Skipping lib /lib32/libc.so.6, libabi=0x0101000300000000 != objabi=0x0201003e00000000
dpkg-shlibdeps: debug: Library libc.so.6 found in /lib/x86_64-linux-gnu/libc.so.6
dpkg-shlibdeps: debug: No associated package found for /home/kubo39/.anyenv/envs/rbenv/versions/2.5.8/lib/libruby.so.2.5
dpkg-shlibdeps: debug: Using shlibs+objdump for libruby.so.2.5 (file /home/kubo39/.anyenv/envs/rbenv/versions/2.5.8/lib/libruby.so.2.5)
dpkg-shlibdeps: debug:  Looking up shlibs dependency of libruby.so.2.5 provided by ''
dpkg-shlibdeps: debug:  Found nothing
dpkg-shlibdeps: debug: No shlibs+objdump info available, trying next package for /home/kubo39/.anyenv/envs/rbenv/versions/2.5.8/lib/libruby.so.2.5
dpkg-shlibdeps: error: no dependency information found for /home/kubo39/.anyenv/envs/rbenv/versions/2.5.8/lib/libruby.so.2.5 (used by ruby)
Hint: check if the library actually comes from a package.

ん?と思ってlddみるとlibruby.soとかいうのリンクしてる。これは自前ビルドしたやつにはなかったような。

$ ldd ruby
        linux-vdso.so.1 (0x00007fff7c5be000)
        libgtk3-nocsd.so.0 => /usr/lib/x86_64-linux-gnu/libgtk3-nocsd.so.0 (0x00007f27f31ad000)
        libruby.so.2.5 => /home/kubo39/.anyenv/envs/rbenv/versions/2.5.8/lib/libruby.so.2.5 (0x00007f27f2c79000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f27f2888000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f27f2684000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f27f2465000)
        libgmp.so.10 => /usr/lib/x86_64-linux-gnu/libgmp.so.10 (0x00007f27f21e4000)
        libcrypt.so.1 => /lib/x86_64-linux-gnu/libcrypt.so.1 (0x00007f27f1fac000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f27f1c0e000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f27f35b6000)

とりあえずconfigureの引数知りたいな、ってときは RbConfig::CONFIG が使える。

$ irb
irb(main):001:0> RbConfig::CONFIG["configure_args"]
=> " '--prefix=/home/kubo39/.anyenv/envs/rbenv/versions/2.5.8' '--enable-shared' 'LDFLAGS=-L/home/kubo39/.anyenv/envs/rbenv/versions/2.5.8/lib ' 'CPPFLAGS=-I/home/kubo39/.anyenv/envs/rbenv/versions/2.5.8/include '"

--enable-shared ってオプションがそれっぽい。

なるほどね。

おまけ

なぜかはわからないけど、rbenvで入れたやつはソースコードはおろかMakefileもconfigure残ってない(ソースからビルドしてるはずなので、わざわざ消しているのだろう。容量削減?)
かわりに自前ビルドしたやつのほうをみてみる。

$ ./configure --help| grep enable-shared
  --enable-shared         build a shared library for Ruby

うーん、まあそうなんだろうけど、rubyバイナリ自身が依存してるのはなんでだろ。
C拡張ライブラリ用とかそういう感じな気がするけどよくわからなかった。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rubyのconfigure時のオプション知りたかったら `RbConfig::CONFIG["configure_args"]` をみる

tl;dr

  • crubyのconfigure時のオプション知りたかったら RbConfig::CONFIG["configure_args"] をみる。

環境

$ uname -mrv
4.15.0-124-generic #127-Ubuntu SMP Fri Nov 6 10:54:43 UTC 2020 x86_64
$ cat /etc/issue
Ubuntu 18.04.5 LTS \n \l

$ rbenv --version
rbenv 1.1.2-34-g0843745
$ ruby -v
ruby 2.5.8p224 (2020-03-31 revision 67882) [x86_64-linux]

本題

rbenvで入れたバイナリでdpkg-shlibdepsかけたらなんか言われた。

$ pwd
/home/kubo39/.anyenv/envs/rbenv/versions/2.5.8/bin
$ mkdir debian;touch debian/control
$ dpkg-shlibdeps -v -v ruby
dpkg-shlibdeps: debug: >> Scanning ruby (for Depends field)
dpkg-shlibdeps: debug: Library libruby.so.2.5 found in /home/kubo39/.anyenv/envs/rbenv/versions/2.5.8/lib/libruby.so.2.5
dpkg-shlibdeps: debug: Skipping lib /lib/i386-linux-gnu/libc.so.6, libabi=0x0101000300000000 != objabi=0x0201003e00000000
dpkg-shlibdeps: debug: Skipping lib /lib32/libc.so.6, libabi=0x0101000300000000 != objabi=0x0201003e00000000
dpkg-shlibdeps: debug: Skipping lib /libx32/libc.so.6, libabi=0x0101003e00000000 != objabi=0x0201003e00000000
dpkg-shlibdeps: debug: Skipping lib /lib32/libc.so.6, libabi=0x0101000300000000 != objabi=0x0201003e00000000
dpkg-shlibdeps: debug: Library libc.so.6 found in /lib/x86_64-linux-gnu/libc.so.6
dpkg-shlibdeps: debug: No associated package found for /home/kubo39/.anyenv/envs/rbenv/versions/2.5.8/lib/libruby.so.2.5
dpkg-shlibdeps: debug: Using shlibs+objdump for libruby.so.2.5 (file /home/kubo39/.anyenv/envs/rbenv/versions/2.5.8/lib/libruby.so.2.5)
dpkg-shlibdeps: debug:  Looking up shlibs dependency of libruby.so.2.5 provided by ''
dpkg-shlibdeps: debug:  Found nothing
dpkg-shlibdeps: debug: No shlibs+objdump info available, trying next package for /home/kubo39/.anyenv/envs/rbenv/versions/2.5.8/lib/libruby.so.2.5
dpkg-shlibdeps: error: no dependency information found for /home/kubo39/.anyenv/envs/rbenv/versions/2.5.8/lib/libruby.so.2.5 (used by ruby)
Hint: check if the library actually comes from a package.

ん?と思ってlddみるとlibruby.soとかいうのリンクしてる。これは自前ビルドしたやつにはなかったような。

$ ldd ruby
        linux-vdso.so.1 (0x00007fff7c5be000)
        libgtk3-nocsd.so.0 => /usr/lib/x86_64-linux-gnu/libgtk3-nocsd.so.0 (0x00007f27f31ad000)
        libruby.so.2.5 => /home/kubo39/.anyenv/envs/rbenv/versions/2.5.8/lib/libruby.so.2.5 (0x00007f27f2c79000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f27f2888000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f27f2684000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f27f2465000)
        libgmp.so.10 => /usr/lib/x86_64-linux-gnu/libgmp.so.10 (0x00007f27f21e4000)
        libcrypt.so.1 => /lib/x86_64-linux-gnu/libcrypt.so.1 (0x00007f27f1fac000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f27f1c0e000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f27f35b6000)

とりあえずconfigureの引数知りたいな、ってときは RbConfig::CONFIG が使える。

$ irb
irb(main):001:0> RbConfig::CONFIG["configure_args"]
=> " '--prefix=/home/kubo39/.anyenv/envs/rbenv/versions/2.5.8' '--enable-shared' 'LDFLAGS=-L/home/kubo39/.anyenv/envs/rbenv/versions/2.5.8/lib ' 'CPPFLAGS=-I/home/kubo39/.anyenv/envs/rbenv/versions/2.5.8/include '"

--enable-shared ってオプションがそれっぽい。

なるほどね。

追記

ビルド時っていうとこういうのあるので言葉がよくない。

irb(main):002:0> RbConfig::CONFIG["CXXFLAGS"]
=> "-O3 -ggdb3 -Wall -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Wno-tautological-compare -Wno-parentheses-equality -Wno-constant-logical-operand -Wno-self-assign -Wunused-variable -Wimplicit-int -Wpointer-arith -Wwrite-strings -Wdeclaration-after-statement -Wimplicit-function-declaration -Wdeprecated-declarations -Wmisleading-indentation -Wno-packed-bitfield-compat -Wsuggest-attribute=noreturn -Wsuggest-attribute=format -Wimplicit-fallthrough=0 -Wduplicated-cond -Wrestrict"
irb(main):003:0> RbConfig::CONFIG["CFLAGS"]
=> "-O3 -ggdb3 -Wall -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Wno-tautological-compare -Wno-parentheses-equality -Wno-constant-logical-operand -Wno-self-assign -Wunused-variable -Wimplicit-int -Wpointer-arith -Wwrite-strings -Wdeclaration-after-statement -Wimplicit-function-declaration -Wdeprecated-declarations -Wmisleading-indentation -Wno-packed-bitfield-compat -Wsuggest-attribute=noreturn -Wsuggest-attribute=format -Wimplicit-fallthrough=0 -Wduplicated-cond -Wrestrict  -fPIC"
irb(main):004:0> RbConfig::CONFIG["LDFLAGS"]
=> "-L. -L/home/kubo39/.anyenv/envs/rbenv/versions/2.5.8/lib  -fstack-protector -rdynamic -Wl,-export-dynamic"

おまけ

なぜかはわからないけど、rbenvで入れたやつはソースコードはおろかMakefileもconfigure残ってない(ソースからビルドしてるはずなので、わざわざ消しているのだろう。容量削減?)
かわりに自前ビルドしたやつのほうをみてみる。

$ ./configure --help| grep enable-shared
  --enable-shared         build a shared library for Ruby

うーん、まあそうなんだろうけど、rubyバイナリ自身が依存してるのはなんでだろ。
C拡張ライブラリ用とかそういう感じな気がするけどよくわからなかった。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails]ぱんくずリスト機能について

はじめに

今度はぱんくず機能を実装復習しましたのでまたすぐ実装できるように

記していきたいと思います。

実装していきます。:fire::fire:

ぱんくず機能とは

現在どこのページにいるのかを視覚的にわかりやすくした表示できる機能ことです。

物語の「ヘンゼルとグレーテル」のなかで、ヘンゼルとグレーテルの二人が森の中で道に迷わないように歩きながら来た道の目印にぱんくずを落としていったことから"ぱんくず機能"で、gemの名前が「gretel」なのだそうです。

可愛いですね :bread:

ちなみに、ヘンゼルは男の子の方でグレーテルは女の子です。:couple:

[gem gretel] 詳細

実装

「gretel」というgemを「Gemfile」に記述し

Gemfile
gem 'gretel'

インストールします。

bundle install

こちらを入力すると「config」ディレクトリの下に「breadcrumbs.rb」ファイルが生成されます。

rails g gretel:install

config/breadcrumbs.rb

設定ファイルを編集します。

config/breadcrumbs.rb
# crumb "現在のページ(表示させるページにも記述)" do
# link "ぱんくずリストでの表示名", "アクセスしたいページのパス"
# parent "親要素のページ(前のページ)"


crumb :pics do
  link "Home", root_path
end

crumb :advises do 
  link "相談一覧", advises_path
  parent :pics
end

crumb :new_advise do 
  link "相談新規投稿", new_advise_path
  parent :advises
end

crumb :show_advise do 
  link "相談詳細", advise_path
  parent :advises
end

viewファイル

オプションの「pretext」を使い
文字を入力するとその文字が出力されます。

「separator」を使い
"&rsaquo;" を記入すると「 > 」 が出力されます。

application.html.erb
<p><%= breadcrumbs pretext: "You are here: ",
                                      separator: "&rsaquo;" %></p>

1.

pics/index.html.erb
<% breadcrumb :pics %>

2.

advise/index.html.erb
<% breadcrumb :advises %>

このように出力されます。

スクリーンショット 2021-01-17 11.24.09.png

3.

advises/new.html.erb
<% breadcrumb :new_advise %>

このように出力されます。

スクリーンショット 2021-01-17 11.23.24.png

4.

advises/show.html.erb
<% breadcrumb :show_advise, @advise %>

このように出力されます。

スクリーンショット 2021-01-17 11.22.50.png

表示されました!!:sparkles:

まとめ

初めてnewファイルやshowファイルにぱんくず機能を実装したので少し時間がかかりましたが
無事実装することができました!!

自分がどこにいるかが把握できて便利ですね。

オプションも他にもあるようなのでまた違うのもしてみたいと思います。

ちなみに

こちらではこのように書かれています。
Forum:パンくずリストの設置場所はページの上、それとも下?

グーグルのジョン・ミューラー氏にツイッターでフォロワーが質問した。

ミューラー氏はこう答えた。

どこに設置しても構わない。

個人的なアドバイスをするなら、ユーザーインターフェイス要素をページに追加するときは使いやすくすることを推奨する(そうでなければ、追加する意味がないはず)。しかしながら、使いやすいかどうかはサイトによる。そしてサイトのことをいちばんよく知っているのはあなただ。

なるほどー
では本日はこれで終わりたいと思います!!

参考

DoRuby:gretelでパンくずリストを作成

virtualiment:Ruby on Railsでパンくずリストを表示するGem gretelの使い方メモ

githubから詳細が見れます。
GitHub gretel

omake:relaxed:

押さえておきたいWeb知識:[Ruby on Rails] appディレクトリとconfigディレクトリを分かりやすく解説します!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

繰り返し処理

繰り返し処理とは

10回同じ処理をするのに10回同じコードを書いていたら大変で見づらいコードになってしまいます。書くのも大変だし修正があったときはめんどくさいです。
そうならないために同じ処理を何回も繰り返したい時に使う処理です。

timesメソッド

同じ処理を複数回繰り返したい時に使うメソッド

数値.times do
  # 繰り返す処理
end

例えば

5.times do
  puts "hello"
end

hello
hello
hello
hello
hello

と出力される

ブロック変数

メソッドの中だけで使用できる変数を||で囲うブロックを使うことで違う処理が実行できます。
ブロックで囲まれた変数をブロック変数と呼ぶ。

timesメソッドのブロック変数には、繰り返し処理が1回実行されるごとに、0から1ずつ増加する数値が代入されます。

数値.times do |ブロック変数|   #繰り返すたびに 0から1ずつ増えていく
  # 繰り返す処理
end

例えば

5.times do |i| #ブロック変数としてiを定義
  puts i + 2
end

2
3
4
5
6

と出力される。

eachメソッド

配列の中に入っている要素ひとつひとつに対して、要素の数だけ繰り返し処理が行なわれるメソッドです。

配列.each do |item|
  # 処理
end

eachに続けてdoとendの間に繰り返したい処理を記述します。
ブロック変数には配列の要素が入り、繰り返すたびに置き換えられます。

例えば

animals = ["cat","dog","rabbit"]   ##配列を定義

animals.each do |animal|
  puts "動物:#{animal}"
end

動物:cat
動物:dog
動物:rabbit

と出力される。

以上です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby チェリー本復習

なにこれ

筆者がチェリー本を読んだ時のメモをまとめた記事です。

ぼっち演算子「&.」

変数(レシーバー)がnilだった場合はnilを返して、nilじゃなければ右辺の処理を実行する
変数に値がある or nilか確定できない時に使うと簡潔に書ける。

user = suga
p user&.upcase #=> SUGA

user = nil
p user&.upcase #=> nil

ちなみにそのままnilにupcaseメソッドを使うと下記のエラーが出る

user = nil
p usesr.upcase

undefined method `upcase' for nil:NilClass (NoMethodError)
# NoMethodError:NilClassのnilオブジェクトにupcaseメソッドは定義されてません

rubyは配列の最後にカンマをつける文化らしい

jsonとかとは違って厳密に管理しないから、配列の最後にカンマをつけるみたい。
「カンマつけるかどっちでも良い=じゃあつけよう!」みたいな感じですかね。

array = [
  'hoge',
  'fuga',
  'piyo',
]

**でハッシュを展開する

h={hoge: 'hoge', piyo: 'piyo'}
p a = { fuga: 'fuga', **h } #=> {:fuga=>"fuga", :hoge=>"hoge", :piyo=>"piyo"}

配列を順番に処理する時、「&:method」を使う

内部にprocをつかうことで引数にブロックを取れる

a = ['a','b','c']
p a.map(&:upcase)

nilが渡される可能性のある配列は、Array(users)みたいにArrayクラスを定義して、引数に変数を渡せば処理できる。nilの場合は[ ]が返る

||=

railsとかのソースコードでよく見るこれ。毎回忘れるので備忘録として書きます。
下記は全て同じ意味。省略して書けるのがメリットです。

test = nil
p test ||= 'hoge' #=> ‘hoge’

p obj.foo #=> nil
p obj.foo || (obj.foo = true) #=> true

test = nil
if test.nil?
  p 'hoge'
else
  p test
end #=> ‘hoge’
test = 'fugaaaaaaaaaaaa’
p test ||= 'hoge #=> ‘fugaaaaaaaaaaaa’

test = 'fugaaaaaaaaaaaa’
if test.nil?
  p 'hoge'
else
  p test
end #=> ‘fugaaaaaaaaaaaa’

any?メソッド

一つ以上条件が満たせばtrueを返す

array_and_nil = [1, 2, nil, nil, 5]
p array_and_nil.any?(&:nil?) #=> true
require 'active_support/all'

hoge = nil
def piyo(hoge)
  hoge || return
end
piyo(hoge) #=> nil

2重for文を避けられる。でも使い所が難しそう

tx = %w(1 2 3 4 5)
ty = %w(a b c d e)

for point in tx.product(ty)
  p(point)
end

&:

下記みたいなコード。渡すブロックを省略できる。

これができる条件
1.ブロック引数が1個だけ
2.ブロックの中で呼び出すメソッドには引数がない
3.ブロック引数にメソッドを1回呼び出す以外の処理がない

n=[1,2,3,4,5,6]
n2=n.select(&:even?)

attr_accessor

呼び方は、個人的にアトリビュートアクセッサーって読んでる。
周りの人はアクセッサーって言ってるかも

役割は、端的に言うと下記のコードを1行で書ける

  def name
    @name
  end

  def name=(name)
    @name = name
  end

上の6行のコードが次の1行になる

  attr_accessor :name

インスタンスからクラスメソッドを呼び出す方法

self.class.【クラスメソッド】すればおk

class User
  def self.self_
    p 'self'
  end
  def instance_
    self.class.self_
  end
end
a = User.new
a.instance_ #=> 'self'

既存のメソッドのエイリアスを作成した後にメソッドを上書き➡️prepend?

特定のオブジェクトだけに結びつくのが、特異メソッド(シングルトンオブジェクトとも言う)

hoge = 'hoge'
def hoge.hello
  p 'hoge!'
end
hoge.hello #=> 'hoge!'

includeはモジュールのメソッドをインスタンスから呼べるようにする。
extendはクラスメソッドにする

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails]テーブルから無作為で1つレコードが欲しい時 .sample使えた。

課題と結論

テーブルから無作為にレコードが欲しいと思ったら普通に .sample使えました。

irb(main):005:0> User.all.sample(1)
=> [#<User id: 5, name: 'aho'>]

地味に知らなかった基礎。

参考情報

ActiveRecord::Relationとは一体なんなのか
https://doruby.jp/users/whale/entries/ActiveRecord--Relation%E3%81%A8%E3%81%AF%E4%B8%80%E4%BD%93%E3%81%AA%E3%82%93%E3%81%AA%E3%81%AE%E3%81%8B

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsでユーザーフォロー機能を実装する(Ajax使うよ)②

何をしたか

この記事は、こちらの記事の続きです。

▼前回の記事
Railsでユーザーフォロー機能を実装する(Ajax使うよ)①

Railsの課題を実施しています。Userのフォロー機能を実装することになりました。
前回までの記事では、マイグレーションファイルの作成と、モデルファイルへのアソシエーションの定義が終わったので、今回はcontrollerview、そしてモデルメソッドを追加していきます。

なお、実行環境は以下の通りです。

  • Rails 5.2.3
  • Ruby 2.6.0

ゴール

今回のゴールはこんな感じです。ボタンを押すとサクサクと非同期でフォロー/フォロー解除のボタンが現れます。

Image from Gyazo

仕様

この機能の使用は以下の通りです。

  • ユーザーは他のユーザーをフォローできる
  • 同じユーザーを2回フォローはできない
  • ユーザーは自分をフォローできない

データ構造

また、DBの設計は下記の通りです。
Image from Gyazo

なぜこうなるのかは、前回の記事を読んでくださいね:relaxed:

非同期ではない実装

まずは、非同期ではない形で実装していきます。
controllermodelともにさらっと書いていきますので、詳しく知りたい方はこの辺の記事をご覧になると良いかもしれません。

controller

controllerの記載は以下の通りです。

relationships_controller.rb
class RelationshipsController < ApplicationController
  def create
    @other_user = User.find(params[:follower])
    current_user.follow(@other_user)
  end

  def destroy
    @user = current_user.relationships.find(params[:id]).follower
    current_user.unfollow(params[:id])
  end
end

followunfollowはモデルメソッドです。後ほど解説します。

view

ビューファイルの記述は以下の通りです。なお、装飾のためのクラスは省いています。なお、user(それぞれのユーザー)を表す変数がここに表示しているコードの外から渡っているものとします。

view
- if logged_in? && current_user != user
  - if current_user.following?(user)
    = button_to 'フォロー解除', relationship_path(current_user.relationships.find_by(follower: user)), method: :delete
  - else
    = button_to 'フォロー', relationships_path(follower: user)

following?もモデルメソットです。

model

userモデルのモデルメソッドとして、followunfollowfollowing?メソッドを、それぞれ定義します。

class User < ApplicationRecord
  # 前回の記事で定義した部分
  has_many :relationships, dependent: :destroy
  has_many :followings, through: :relationships, source: :follower

  has_many :passive_relationships, class_name: 'Relationship', foreign_key: 'follower_id', dependent: :destroy
  has_many :followers, through: :passive_relationships, source: :user

  # 今回追記したモデルメソッド
  def follow(other_user)
    return if self == other_user

    relationships.find_or_create_by!(follower: other_user)
  end

  def following?(user)
    followings.include?(user)
  end

  def unfollow(relathinoship_id)
    relationships.find(relathinoship_id).destroy!
  end
end

なお、このクラスの上方にあるのは、前回の記事で適宜した複雑なアソシエーションです。

非同期ではない通信での実装完了

ここまでで、Ajaxではないフォロー機能は完成しています。デモ用にredirect_toで画面を遷移させているので、若干非同期っぽくも見えますが、「フォロー」ボタンを押して画面をリロード後「フォロー解除」ボタンが現れます。

Image from Gyazo

Ajaxでの実装

それでは、これを非同期の通信にしていきます。こちらもさらっと書いていますので、どうしてそうなるのかが気になる方は、こちらの記事をご覧ください。

remote: trueでajaxの投稿をPOSTをするよ。

html部分

まずは、ボタン部分はremote: trueオプションをつけて、パーシャルに切り出します。

views/relationships/_follow_button.html.slim
= button_to 'フォロー', relationships_path(follower: user), remote: true
views/relationships/_unfollow_button.html.slim
= button_to 'フォロー解除', relationship_path(current_user.relationships.find_by(follower: user)), method: :delete, remote: true
# もともとボタンのあったビューファイル
- if logged_in? && current_user != user
 div id="follow-button-#{user.id}"
   - if current_user.following?(user)
      = render 'relationships/unfollow_button', user: user
   - else
      = render 'relationships/follow_button', user: user

**.js.erb ファイルを作る

動的に呼び出す部分のファイルは、**.js.erbファイルに書き出します。

views/relationships/create.js.erb
$("#follow-button-<%= @other_user.id %>").html("<%= j(render 'unfollow_button', user: @other_user) %>")
views/relationships/destroy.js.erb
$("#follow-button-<%= @user.id %>").html("<%= j(render 'follow_button', user: @user) %>")

完成!

こちらで完成です^^Ajaxにするのはビューファイルを書き換えるだけで終わりました:relaxed:
シンプルー:sparkles:

Image from Gyazo

感想など

フォロー・フォロー解除機能は、データ構造8割!といった感じで、DBとモデルの設計がやたら複雑なんですね〜
しっかり読み解けてよかったです^^

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsでユーザーフォロー機能を実装する(Ajax使うよ)①

何をしたか

Railsの課題を実施しています。Userのフォロー機能を実装することになりました。
この機能は前に実装したことはあって、「確かあのアソシエーションが難しいやつ」ぐらいには覚えていました。

たまたま、この機能の実装を人に教える機会もありそうだったので、しっかり教えられるように手順を細かく記すことにしました。

ただ、かなりの長文になってしまったので前後編に分けています。この記事ではDB設計〜アソシエーションまでの話をして、続きは下記の記事になります。

Railsでユーザーフォロー機能を実装する(Ajax使うよ)②

なお、実行環境は以下の通りです。

  • Rails 5.2.3
  • Ruby 2.6.0

ゴール

今回、作るものはユーザーのフォロー機能です。ボタンを押すと、ユーザーをフォロー、もう一度ボタンを押すと、フォロー解除できます。

Image from Gyazo

また、この機能のために作成したモデルは下記の通りです。

Image from Gyazo

謎すぎる形態をしていますよね:sweat_smile:
いきなり、上記のモデルに行き着くのは難しいので、ひとつひとつ分解して考えていきます。

なお、以下はあくまでも「私はこう考えた」考え方ですので、人によっては他の考え方の方がしっくりくるかもしれません。

実装

分解して考える

まずは、「ユーザー」と「フォロワー」という登場人物を作った方がわかりやすいので、
Userモデルを(頭の中で)UserモデルとFollowerモデルに分解します。

Image from Gyazo

この中で、一番簡単そうなUserがたくさんの人をフォローしている状況から考えていきましょう。

Image from Gyazo
この場合、Userモデルに対し

has_many: followings, through: :relationships

というアソシエーションを(頭の中で)仮置きします。ただし、Userモデル = Followerモデルであることは忘れないでください。

上記の関係を、マイグレーションファイルで表すとこうなります。

db/migrate/XXXXXXXX_create_relationships.rb
class CreateRelationships < ActiveRecord::Migration[5.2]
  def change
    create_table :relationships do |t|
      t.references :user
      t.references :follower, foreign_key: { to_table: :users }

      t.timestamps

      t.index [:user_id, :follower_id], unique: true
    end
  end
end

followersテーブルは実際には存在しないので、foreign_key: { to_table: :users }で、「followerを探すときはusersテーブル(のfollower_id)を見てね」とRailsに伝えています。

この辺りの実装は、↓この記事が大変参考になりました。

マイグレーションにおいて参照先テーブル名を自動で推定できないカラムを外部キーとして指定する方法

また、同じ人を2回フォローできないように

t.index [:user_id, :follow_id], unique: true

user_idカラムとfollower_idのカラムの組み合わせに、重複した値が入らないようにする制約を加えています。

アソシエーションの記載

Usersモデル

この時、Userモデルのアソシエーションの記述は下記のようになります。

models/user.rb
class User < ApplicationRecord
  has_many :relationships, dependent: :destroy
  has_many :followings, through: :relationships, source: :follower
end

ポイントは、以下の通りです。

若干複雑になってきましたね...:frowning2:
難しそうなところにはリンクも貼りましたので、ひとつづつ読み解いてみてください。

ところで、Followerモデルなんてないのに、どうやってFollowerモデルを参照するの??という件については、次のRelationshipモデルのアソシエーションをご覧ください。

Relationshipモデル

Relationshipモデルの記載内容は下記の通りです。

models/relationship.rb
class Relationship < ApplicationRecord
  belongs_to :follower, class_name: 'User'
end

このように記載することで、Followerモデルの参照がきたらUserモデルを参照するようにRailsに伝えています。

余談: sourceclass_nameの違いについて

ところで、さっきはsourceで別のモデルを参照したのに、今度はなんでclass_nameなの?って思いませんでしたか?(私は思いました)

その理由は、こちらに書いてあって、
Rails: difference between :source => ?? and :class_name => ?? in models

  • source ... has_many :****, through: :****の時に使う
  • class_name ...has_many :***の時に使う

だそうです:smile:知らなかった!!

確認

ここで、一回きちんとアソシエーションが定義できているか確かめることをお勧めします。私は、こんなふうに確かめました。

$ rails c
> user = User.first
> user.relationships
# => []
> user.relationships.create!(follower_id: 2)
# => Relationship のレコードが表示
> user.followings
# => フォローしているUser(user_idが2のユーザー)のレコードが表示

フォロー中のユーザーのレコードが呼び出されたので、id:1のユーザーはid:2のユーザーをフォローできていると言えます。

逆の関係も考える

さて、それでは今度はユーザーがたくさんのフォロワーにフォローされているという、先程どは逆の状況も考えてみたいと思います。

まず、ゴールなのですが、先程の逆の矢印を定義できれば良いです。
具体的に図に書き込んでみます。

Image from Gyazo

followerがたくさんのuserrelationshipsを通じて持っている、こんな図が出来上がります。

でも、Followerモデルは実際には存在せず、Userモデルとイコールでしたね。
そのため、主語をUserに書き換えてみます。

Image from Gyazo

Userrelationshipsを通じて、followersをたくさん持っている。
言葉としてはわかりやすいのですが、今度は、頭の中に作ったFollowモデルが邪魔になってきました。

followersテーブルを置いたために考えるのが難しくなってきているので、FollowモデルとUserモデルを一つにまとめました。

Image from Gyazo

だいぶ、一番初めに提示したER図に近づいてきましたね:grin:

ついでに、先程の赤い矢印も復活させてみました。
すると、今度はthrough: :relationshipsの部分で、名前が重複しているのがわかります。

Image from Gyazo

そこで、今度は片方の名前を変えて、userfollowerにフォローされている、と言う意味でpassive_relationshipsと名付けました。

これで、最初に提示したER図と同じになっています:relaxed:

アソシエーションの記載

Userモデル

では、この関係を実際にモデルに表していきます。
まず、Userモデルはこうなります。

models/user.rb
class User < ApplicationRecord
  has_many :relationships, dependent: :destroy
  has_many :followings, through: :relationships, source: :follower

  has_many :passive_relationships, class_name: 'Relationship', foreign_key: 'follower_id', dependent: :destroy # 追記1
  has_many :followers, through: :passive_relationships, source: :user # 追記2
end

めっちゃ複雑になってきましたね:joy:ひとつひとつ読みといていくと、まず、追記1の部分は

  • Userはたくさんのpassive_relationshipsを持っています。
  • この時、参照して欲しいクラスはRelationshipです。
  • 外部キーとしてfollower_idを使います。

というのを表しています。
次に、追記2の部分は

  • Userはたくさんのfollowersを、passive_relationshipsを通じて持っています。
  • passive_relationshipsは、直前の定義によりRelationship、クラスを参照するようになっています。

複雑すぎて憤死しそうです:joy:
ワンステップずつ丁寧に書いたつもりなので、丁寧に読んでみてください:sweat_smile:

Relarionshipモデル

最後に、Relationshipモデルに追記した内容を紹介します。

models/relationship.rb
class Relationship < ApplicationRecord
  belongs_to :user # 追記
  belongs_to :follower, class_name: 'User'
end

こちらは逆にシンプルすぎて心配になるレベルですが、こちらはこれで完了です:innocent:

確認

ここで、1回確認をしてみます。先程、コンソールでid:1のユーザーがid:2のユーザーをフォローすると言うデータは作りましたので、id:2のユーザーは、id:1のユーザーにフォローされているはずです。

それを、コンソールで試してみます。

$ rails c
> user2 = User.second
> user2.followers
# => id:1のUserのレコードが表示される

user2をフォローしているユーザーが取得できました!!成功です:smile:

to be contenued ...

これからいよいよviewやcontrollerを実装!...となっていくのですが、
ここからは次回に続きます。

Ajax出てこないじゃん!と思った方、ごめんなさい。次回に出てきます。。。

▼この話の続編はこちら
Railsでユーザーフォロー機能を実装する(Ajax使うよ)②

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby初心者向け】配列の要素を自由に削除する方法を解説!

配列の中の"特定の要素を消すメソッド"をお探しですか?

当記事では、それに該当するdelete()とdelete_ifを紹介します!

Ruby初心者に向けてできるだけ丁寧に解説していきますので、是非最後までお付き合いください!

配列の特定の要素を削除するdelete( )

まずは指定した要素を削除することができるdelete( )を紹介します。

このメソッドは引数として削除したい要素を指定してあげるだけで、その引数と一致する要素を配列から削除することができます。

delete()の使用方法
a = [1, 2, 3, 1, 2, 3]

#配列から3の要素だけ削除する

a.delete(3)

a  #=> [1, 2, 1, 2]

上記はdelete( )の使用例です。

まずはaに配列を引数として渡してあげて、aに対してdelete( )メソッドを使って3という要素を削除するように命令します。

そして、正確に実行されると、上記のような結果になるわけです。

削除する配列の要素の条件を指定するdelete_if

次にdelete_ifについて解説していきます。

delete_ifは、delete( )と比べると広範囲な配列の要素の削除が可能です。

例えば、配列内の奇数の要素だけを削除したいとします。

a = [1, 2, 3, 1, 2, 3]

#配列から奇数の要素だけを削除する

a.delete_if do |n|

 n.odd?

end

a  #=> [2, 2]

まず、配列を用意します。

そして、delete_ifで奇数である場合に要素を削除するように命令します。

結果として、奇数が削除されます。

まとめ

ターミナルなどで配列を操作したいときにこのようなメソッドを覚えていると便利ですね。

初心者の方は忘れがちなメソッドなので、覚えておくと少し他の人と差別化することができるかもしれませんね!

これからそのような情報を記事として取り上げていこうと思っているので、よかったら見て頂けると幸いです!

ではまた!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails + Webpacker】assetsの画像を使いたい! Vue.jsで画像を表示できるまで

RailsとWebpackerで開発している時に、画像どうやって読み込むのかなと思って調べてみた記録です。

WebpackerのREADMEをのぞいてみる

WebpackerのREADMEの Paths > resolved を参照してみると、assetsをもつアプリとimagesを共有したいときは、webpacker.ymlresolved_pathsと書いて読み込める、とあります。今回はこれに習って実装しています。

config/webpacker.yml
resolved_paths: ['app/assets']

ただし、コンパイルの速度に影響アリ

以下にあるように…

Please be careful when adding paths here otherwise it will make the compilation slow, consider adding specific paths instead of whole parent directory if you just need to reference one or two modules

でかいディレクトリ単位で読み込むとコンパイルが遅くなる、ということのようです。表示速度を気にする場合は注意したいです。

実装例

webpacker.ymlにpathをかく

上でみたように webpacker.ymlに記述していきます。今回はassets/images配下しか必要としていないので、先ほどの注意点も考慮してimagesまでpathを指定してみました。

config/webpacker.yml
  resolved_paths: ['app/assets/images']

Vue.jsで使うには

今回は、Vue.jsのコンポーネントで読み込みたかったので、一緒に書いておきます。

sample.vue
<template>
  <div>
    <!-- imgタグでsrcに"~"をつけてimportしたファイルを指定する -->
    <img src="~logo.svg" /> 
  </div>
</template>

<script>
  import 'logo.svg'; // ここでimport
</script>

こうやって書いてみるととってもシンプルですね。

以上、少しでも参考になれば嬉しいです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

開発環境にRailsをインストール・新規アプリ作成

引用先
Railsチュートリアル

Railsをインストール

Rubyドキュメントをインストールしないよう.gemrcファイルを設定

$ echo "gem: --no-document" >> ~/.gemrc

Railsをインストールするには、gemコマンドを使います。
Rubyドキュメントのインストールで無駄な時間を使わないよう、コマンドに設定を追加しています。

バージョンを指定してRailsをインストール

$ gem install rails -v 6.0.3

バージョン6.0.3でインストール

$ rails -v
# Rails 6.0.3

バージョンの確認(指定してインストールした場合は合っているか確認)

JavaScriptソフトウェアの依存関係を管理するYarnをインストール

$ source <(curl -sL https://cdn.learnenough.com/yarn_install)

※警告メッセージがでた場合

========================================
  Your Yarn packages are out of date!
  Please run `yarn install --check-files` to update.
========================================
$ yarn install --check-files

上記を実行でOK


新規アプリ作成

Railsプロジェクト用のenvironmentディレクトリを作る

$ cd                    # プロジェクトのホームディレクトリに移動
$ mkdir environment     # environmentディレクトリを作成
$ cd environment/       # 作成したenvironmentディレクトリに移動

rails newを実行

$ rails _6.0.3_ new <アプリ名>

各フォルダの役割

引用先
Railsチュートリアル 表 1.2: デフォルトのRailsディレクトリ構成の概要

ディレクトリ 用途
app/ モデル、ビュー、コントローラ、ヘルパーなどを含む主要なアプリケーションコード
app/assets アプリケーションで使うCSS(Cascading Style Sheet)、JavaScriptファイル、画像などのアセット
bin/ バイナリ実行可能ファイル
config/ アプリケーションの設定
db/ データベース関連のファイル
doc/ マニュアルなど、アプリケーションのドキュメント
lib/ ライブラリやモジュール置き場
log/ アプリケーションのログファイル
public/ エラーページなど、一般(Webブラウザなど)に直接公開するデータ
bin/rails コード生成、コンソールの起動、ローカルのWebサーバーの立ち上げなどで使うRailsスクリプト
test/ アプリケーションのテスト
tmp/ 一時ファイル
README.md アプリケーションの簡単な説明
Gemfile このアプリケーションに必要なGemの定義ファイル
Gemfile.lock アプリケーションで使われるgemのバージョンを確認するためのリスト
config.ru Rackミドルウェア用の設定ファイル
.gitignore Gitに取り込みたくないファイルを指定するためのパターン

Bundlerを実行

bundlerとは、gemのバージョンやgemの依存関係を管理してくれるgem。
bundlerを使うことで、複数人での開発やgemのバージョンが上がってもエラーを起こさずに開発できます。

Gemfileに使用するgemを記入する

各開発環境によって使用するgemは異なるため必要なgemを記入する。
(例 bootsnap,byebug等)

bundleをインストール

$ cd hello_app/
$ bundle install

エラーで[bundle update]と出たら、bundle updateを先に実行


ここまでが環境構築となります。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ActiveHashの導入と簡単な実装までの流れ

Activehashとは

都道府県名などの変更されないデータをモデルファイル内に直接記述することで、データベースへ保存せずにデータを取り扱うことができるgemです。

もっと簡単にいえば、ActiveHashを導入することで以下のようなプルダウンメニューを作成するときに大いに役立ちます。
スクリーンショット 2021-01-16 23.55.35.png

プルダウンメニューの実装

住んでいる都道府県を投稿するアプリを使って説明します。

ターミナル
rails _6.0.0_ new activehash_app -d mysql
rails db:create

モデル、コントローラー、ビューを用意します。

モデルを作成

ターミナル
rails g model address      

上記コマンドで生成されたマイグレーションファイルに下記の通り、nameカラムとprefecture_idカラムを記述してマイグレートします。
prefecture_idカラムには、後でActiveHash gemで導入するプルダウンメニューの情報が入ります。

2021XXXXXXXXXX_create_addresses.rb
class CreateAddresses < ActiveRecord::Migration[6.0]
  def change
    create_table :addresses do |t|
      t.string :name, null: false
      t.integer :prefecture_id, null: false
      t.timestamps
    end
  end
end
ターミナル
rails db:migrate

コントローラーとビューを作成

下記のコマンドでコントローラーに加えて、一覧表示と新規投稿のビューをまとめて作成します。

ターミナル
rails g controller addresses index new

コントローラーとビュー(indexnew)を以下のように記述します。

app/controllers/addresses_controller.rb
class AddressesController < ApplicationController
  def index
    @addresses = Address.order("created_at DESC")
  end

  def new
    @address = Address.new
  end

  def create
    @address = Address.new(address_params)
    if @address.valid?
      @address.save
      return redirect_to root_path
    else
      render "new"
    end
  end

  private
  def address_params
    params.require(:address).permit(:name, :prefecture_id)
  end
end
app/views/addresses/index.html.erb
<h1>あなたの住んでいる都道府県は?</h1>
<%= link_to "投稿する", new_address_path %>
<div>
  <ul>
    <% if @addresses %>
      <% @addresses.each do |address| %>
      <li>
        <%= address.name %>
        <%= address.prefecture.name %>
      </li>
      <% end %>
    <% end %>
  </ul>
</div>

app/views/addresses/new.html.erb
<%= form_with model: @address, url:addresses_path, local: true do |f| %>
  <div class="article-box">
    あなたの名前と住んでいる都道府県を投稿する
    <div>
      <p><%= f.text_area :name, placeholder:"あなたの名前" %></p>
      <p><%= f.collection_select(:prefecture_id, Prefecture.all, :id, :name, {}, {class:"genre-select"}) %></p>
      <%= f.submit "投稿する" ,class:"btn" %>
    </div> 
  </div>
  <%= link_to "戻る", root_path %>
<% end %>

ActiveHashの導入

いよいよActiveHashを導入します。
Gemfileの一番下に下記の記述をして、ターミナルでbundle installします。

Gemfile
gem 'active_hash'
ターミナル
bundle install

都道府県のリストを用意するため、prefectureモデルを作成します。
ここで、いつものrails g model :モデル名コマンドに--skip-migrationというオプションを付けます。
--skip-migrationはマイグレーションファイルの作成をスキップしてくれるオプションです。都道府県に関する情報はデータベースに保存しないためです。

ターミナル
rails g model prefecture --skip-migration

作成したprefecture.rbに、以下のように記述します。

app/models/prefecture.rb
class Prefecture < ActiveHash::Base
  self.data = [
    {id: 0, name: '--'}, {id: 1, name: '北海道'}, {id: 2, name: '青森県'}, 
    {id: 3, name: '岩手県'}, {id: 4, name: '宮城県'}, {id: 5, name: '秋田県'}, 
    {id: 6, name: '山形県'}, {id: 7, name: '福島県'}, {id: 8, name: '茨城県'}, 
    {id: 9, name: '栃木県'}, {id: 10, name: '群馬県'}, {id: 11, name: '埼玉県'}, 
    {id: 12, name: '千葉県'}, {id: 13, name: '東京都'}, {id: 14, name: '神奈川県'}, 
    {id: 15, name: '新潟県'}, {id: 16, name: '富山県'}, {id: 17, name: '石川県'}, 
    {id: 18, name: '福井県'}, {id: 19, name: '山梨県'}, {id: 20, name: '長野県'}, 
    {id: 21, name: '岐阜県'}, {id: 22, name: '静岡県'}, {id: 23, name: '愛知県'}, 
    {id: 24, name: '三重県'}, {id: 25, name: '滋賀県'}, {id: 26, name: '京都府'}, 
    {id: 27, name: '大阪府'}, {id: 28, name: '兵庫県'}, {id: 29, name: '奈良県'}, 
    {id: 30, name: '和歌山県'}, {id: 31, name: '鳥取県'}, {id: 32, name: '島根県'}, 
    {id: 33, name: '岡山県'}, {id: 34, name: '広島県'}, {id: 35, name: '山口県'}, 
    {id: 36, name: '徳島県'}, {id: 37, name: '香川県'}, {id: 38, name: '愛媛県'}, 
    {id: 39, name: '高知県'}, {id: 40, name: '福岡県'}, {id: 41, name: '佐賀県'}, 
    {id: 42, name: '長崎県'}, {id: 43, name: '熊本県'}, {id: 44, name: '大分県'}, 
    {id: 45, name: '宮崎県'}, {id: 46, name: '鹿児島県'}, {id: 47, name: '沖縄県'}
  ]
  include ActiveHash::Associations #ActiveHashに定義されているモジュールを読み込み
  has_many :address #addressモデルとのアソシエーションを定義
end

都道府県のデータを配列にハッシュ形式で入れます。
また、include ActiveHash::AssociationsでActiveHashに定義されているモジュールを読み込み、has_manyを記述してAddressモデルとのアソシエーションを定義しています。
ActiveHashのモジュールについては公式GitHubのREADMEライブラリを参照してください。

address.rbにも同様に、モジュールを読み込み、belongs_toでPrefectureモデルとのアソシエーションを定義します。

app/models/address.rb
class Address < ApplicationRecord
  extend ActiveHash::Associations::ActiveRecordExtensions #Activehashに定義されているモジュールを読み込み
  belongs_to :prefecture #prefectureモデルとのアソシエーションを定義
end

上記のアソシエーションを定義することで、先ほど作成したindex.html.erb

app/views/addresses/index.html.erb(再掲)
<h1>あなたの住んでいる都道府県は?</h1>
<%= link_to "投稿する", new_address_path %>
<div>
  <ul>
    <% if @addresses %>
      <% @addresses.each do |address| %>
      <li>
        <%= address.name %>
        <%= address.prefecture.name %><%# アソシエーション定義によってprefecure.rbに格納している都道府県名にアクセスできる %>
      </li>
      <% end %>
    <% end %>
  </ul>
</div>

参考資料

ActiveHashの公式GitHub

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ActiveHashの導入目的とアプリへの実装までの簡単な流れ

ActiveHashとは

都道府県名などの変更されないデータをモデルファイル内に直接記述することで、データベースへ保存せずにデータを取り扱うことができるgemです。

ActiveHashを導入する目的

ユーザー情報のような編集されることがあるデータと違って、都道府県名などは変更されないデータなので、データベースにわざわざ保存する必要がありません。

かといってビューに直接都道府県名のプルダウンメニューを作ってしまうと可読性が下がってしまいます。

そこでActiveHashを使ってモデルからデータを呼び出すという方法を採ることでコードの管理がしやすくなります。

また、ActiveHashを導入することで以下のようなプルダウンメニューを作成するときに大いに役立ちます。
スクリーンショット 2021-01-16 23.55.35.png

プルダウンメニューの実装

住んでいる都道府県を投稿するアプリを使って説明します。

ターミナル
rails _6.0.0_ new activehash_app -d mysql
rails db:create

モデル、コントローラー、ビューを用意します。

モデルを作成

ターミナル
rails g model address      

上記コマンドで生成されたマイグレーションファイルに下記の通り、nameカラムとprefecture_idカラムを記述してマイグレートします。
prefecture_idカラムには、後でActiveHash gemで導入するプルダウンメニューの情報が入ります。

2021XXXXXXXXXX_create_addresses.rb
class CreateAddresses < ActiveRecord::Migration[6.0]
  def change
    create_table :addresses do |t|
      t.string :name, null: false
      t.integer :prefecture_id, null: false
      t.timestamps
    end
  end
end
ターミナル
rails db:migrate

コントローラーとビューを作成

下記のコマンドでコントローラーに加えて、一覧表示と新規投稿のビューをまとめて作成します。

ターミナル
rails g controller addresses index new

コントローラーとビュー(indexnew)を以下のように記述します。

app/controllers/addresses_controller.rb
class AddressesController < ApplicationController
  def index
    @addresses = Address.order("created_at DESC")
  end

  def new
    @address = Address.new
  end

  def create
    @address = Address.new(address_params)
    if @address.valid?
      @address.save
      return redirect_to root_path
    else
      render "new"
    end
  end

  private
  def address_params
    params.require(:address).permit(:name, :prefecture_id)
  end
end
app/views/addresses/index.html.erb
<h1>あなたの住んでいる都道府県は?</h1>
<%= link_to "投稿する", new_address_path %>
<div>
  <ul>
    <% if @addresses %>
      <% @addresses.each do |address| %>
      <li>
        <%= address.name %>
        <%= address.prefecture.name %>
      </li>
      <% end %>
    <% end %>
  </ul>
</div>

app/views/addresses/new.html.erb
<%= form_with model: @address, url:addresses_path, local: true do |f| %>
  <div class="article-box">
    あなたの名前と住んでいる都道府県を投稿する
    <div>
      <p><%= f.text_area :name, placeholder:"あなたの名前" %></p>
      <p><%= f.collection_select(:prefecture_id, Prefecture.all, :id, :name, {}, {class:"genre-select"}) %></p>
      <%= f.submit "投稿する" ,class:"btn" %>
    </div> 
  </div>
  <%= link_to "戻る", root_path %>
<% end %>

ActiveHashの導入

いよいよActiveHashを導入します。
Gemfileの一番下に下記の記述をして、ターミナルでbundle installします。

Gemfile
gem 'active_hash'
ターミナル
bundle install

都道府県のリストを用意するため、prefectureモデルを作成します。
ここで、いつものrails g model :モデル名コマンドに--skip-migrationというオプションを付けます。
--skip-migrationはマイグレーションファイルの作成をスキップしてくれるオプションです。都道府県に関する情報はデータベースに保存しないためです。

ターミナル
rails g model prefecture --skip-migration

作成したprefecture.rbに、以下のように記述します。

app/models/prefecture.rb
class Prefecture < ActiveHash::Base
  self.data = [
    {id: 0, name: '--'}, {id: 1, name: '北海道'}, {id: 2, name: '青森県'}, 
    {id: 3, name: '岩手県'}, {id: 4, name: '宮城県'}, {id: 5, name: '秋田県'}, 
    {id: 6, name: '山形県'}, {id: 7, name: '福島県'}, {id: 8, name: '茨城県'}, 
    {id: 9, name: '栃木県'}, {id: 10, name: '群馬県'}, {id: 11, name: '埼玉県'}, 
    {id: 12, name: '千葉県'}, {id: 13, name: '東京都'}, {id: 14, name: '神奈川県'}, 
    {id: 15, name: '新潟県'}, {id: 16, name: '富山県'}, {id: 17, name: '石川県'}, 
    {id: 18, name: '福井県'}, {id: 19, name: '山梨県'}, {id: 20, name: '長野県'}, 
    {id: 21, name: '岐阜県'}, {id: 22, name: '静岡県'}, {id: 23, name: '愛知県'}, 
    {id: 24, name: '三重県'}, {id: 25, name: '滋賀県'}, {id: 26, name: '京都府'}, 
    {id: 27, name: '大阪府'}, {id: 28, name: '兵庫県'}, {id: 29, name: '奈良県'}, 
    {id: 30, name: '和歌山県'}, {id: 31, name: '鳥取県'}, {id: 32, name: '島根県'}, 
    {id: 33, name: '岡山県'}, {id: 34, name: '広島県'}, {id: 35, name: '山口県'}, 
    {id: 36, name: '徳島県'}, {id: 37, name: '香川県'}, {id: 38, name: '愛媛県'}, 
    {id: 39, name: '高知県'}, {id: 40, name: '福岡県'}, {id: 41, name: '佐賀県'}, 
    {id: 42, name: '長崎県'}, {id: 43, name: '熊本県'}, {id: 44, name: '大分県'}, 
    {id: 45, name: '宮崎県'}, {id: 46, name: '鹿児島県'}, {id: 47, name: '沖縄県'}
  ]
  include ActiveHash::Associations #ActiveHashに定義されているモジュールを読み込み
  has_many :address #addressモデルとのアソシエーションを定義
end

都道府県のデータを配列にハッシュ形式で入れます。
また、include ActiveHash::AssociationsでActiveHashに定義されているモジュールを読み込み、has_manyを記述してAddressモデルとのアソシエーションを定義しています。
ActiveHashのモジュールについては公式GitHubのREADMEライブラリを参照してください。

address.rbにも同様に、モジュールを読み込み、belongs_toでPrefectureモデルとのアソシエーションを定義します。

app/models/address.rb
class Address < ApplicationRecord
  extend ActiveHash::Associations::ActiveRecordExtensions #Activehashに定義されているモジュールを読み込み
  belongs_to :prefecture #prefectureモデルとのアソシエーションを定義
end

上記のアソシエーションを定義することで、先ほど作成したindex.html.erbでPrefectureモデルに格納した都道府県名にアクセスできるようになりました。

app/views/addresses/index.html.erb(再掲)
<h1>あなたの住んでいる都道府県は?</h1>
<%= link_to "投稿する", new_address_path %>
<div>
  <ul>
    <% if @addresses %>
      <% @addresses.each do |address| %>
      <li>
        <%= address.name %>
        <%= address.prefecture.name %><%# アソシエーション定義によってprefecure.rbに格納している都道府県名にアクセスできる %>
      </li>
      <% end %>
    <% end %>
  </ul>
</div>

参考資料

ActiveHashの公式GitHub

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DXRuby 1.4.7 でエラーになった時の対処法とインストール方法

Windows向けのRuby用2Dゲームライブラリ「DXRuby」が1.4.7にバージョンアップして、最新のRuby 3.0.0に、そしてついに64bit版Rubyに対応しました。ただし、Windows10で使う場合、エラーになって焦ったので、注意点をメモしておきます。

→ 以前の記事
DXRuby 1.4.6 をWindows10で使う時の注意点とインストール方法

注意点

・ DXRubyは、Windowsでないと動かない

WindowsのDirectXを使うので、macOS、Linuxでは動きません。
Windows環境以外で、DXRubyとほぼ同じコードで動くようにするライブラリとしては、「DXOpal」や「Nyle-canvas」などがあります(ただし、完全互換ではない)。

Rubyのインストールには、「RubyInstaller for Windows」が便利です。DXRuby 1.4.7からは、64bit版Ruby("x64"と書いてある版)に対応しました。
Devkit(MSYS2)付きでなくても、DXRubyはかまいません。

・ 64bit版では、Sound.newでエラーになる

→・[DXRuby 1.4.7] 64bitでは、Sound.newでエラー · Issue #4 · mirichi/dxruby

・ Windows10では、d3dx9_40.dllを追加しないと動かない

これが原因で、DXRubyをインストールしたのに実行するとエラーが出て焦りました。

DXRubyでは、WindowsのDirectX 9ライブラリを使っています。(なので、Windows以外では動かない。)
Window10から、DirectX 9が付属しなくなったので、自分で追加する必要があります。

参考)
→・Windows10では、DXRubyを動かすのに d3dx9_40.dllが必要 · Issue #3 · mirichi/dxruby

※ d3dx9_40.dllのインストール方法

d3dx9_40.dllは、公式のMicrosoftのサイトからダウンロードするのが安全。

  1. DirectX End-User Runtimes(June 2010)をダウンロードする。
    https://www.microsoft.com/en-us/download/details.aspx?id=8109

  2. ダウンロードした directx_Jun2010_redist.exeをダブルクリック。
    適当なフォルダを指定して、解凍する。

  3. 必要なのは d3dx9_40.dllだけなので、解凍先のフォルダの中からRubyの64bit/32bitに合わせて必要なファイルを探す。
    64bit版Ruby(x64)   ;Nov2008_d3dx9_40_x64.cab
    32bit版Ruby(x86、i386);Nov2008_d3dx9_40_x86.cab

  4. Nov2008_d3dx9_40_x64.cab または Nov2008_d3dx9_40_x86.cabをダブルクリックする。

  5. 中の d3dx9_40.dllをダブルクリックして、適当なフォルダを指定して解凍する。

  6. 解凍先のフォルダに d3dx9_40.dllができる。

  7. できた d3dx9_40.dllを Windowsのフォルダにコピーする。
    やり方は2通りある。

 a)インストールしているRubyのフォルダの中の、binフォルダにコピーする。
   C:\Ruby30-x64\bin など

 b)Windowsのプログラムフォルダにコピーする。

  ・64bit版の d3dx9_40.dllの場合;
   C:\Windows\System32フォルダ(こちらが64bit用プログラムフォルダ)

  ・32bit版の d3dx9_40.dllの場合;
   C:\Windows\SysWOW64フォルダ(こちらが32bit用プログラムフォルダ)

   ※プログラムフォルダ名が一見すると逆なので注意!

   > 「対象のフォルダーへのアクセスは拒否されました
   >  このフォルダーへコピーするには管理者の権限が必要です」

   とパネルが出るので、
   続行ボタン
   を押すとコピーされる。

8.(必要ならWindows を再起動する。)

DXRubyのインストール方法

DXRuby 1.4.7のインストールは、RubyGemsからできます。

> gem install dxruby

DXRubyが動作するかの確認

> irb
irb(main):001:0> require 'dxruby'
=> true
irb(main):002:0> exit

trueと表示されればOKです!

参考)

→・グラフィックプログラミングにチャレンジしよう - Rubyではじめようプログラミング - コカネット(子供の科学 WEBサイト)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む