20190627のRubyに関する記事は26件です。

QiitaAPIで各プログラミング言語のタグの記事とフォロワーの数を調べて纏めたりする(pythonとrubyを使う)

今どのプログラミング言語がどれくらい人気なのか気になるので、qiitaで書かれた記事のタグを調べて見ましたが、一々調べるよりもコードを書いてQiitaAPIからデータを取得して分析する方が楽なので、書いてみました。この記事では試してみたこととその結果を纏めてみます。

QiitaAPIについて

QiitaAPIにアクセスしたらタグの記事の数とフォローしている人数を調べることができます。

例えばc++のタグ https://qiita.com/api/v2/tags/c++

QiitaAPIについて詳しくは https://qiita.com/api/v2/docs

このようなjsonデータが出ます

{"followers_count":24875,"icon_url":"https://s3-ap-northeast-1.amazonaws.com/qiita-tag-image/fe7df47710bdae8b8565b323841a6b89e2f66b89/medium.jpg?1515774066","id":"C++","items_count":5919}

使うプログラミング言語

基本的にQiitaAPIのようなAPIは色んな言語で簡単に扱えるようですが、今回はrubypythonを使ってQiitaAPIを通じて色んなプログラミング言語のタグの記事とフォロワーの数を調べて纏めてみます。

最初は全部rubyでやってみたいと思っていたのですが、データの分析やグラフを描くことがやはりpythonのpandasmatplotlibを使ったほうがずっと楽です。

なのでrubyでデータをcsvに保存して、pythonでグラフを描くという形になります。

ここで挙げるのは自分が知っている言語だけです。それ以外知らない言語もあるかもしれないです。その他に、私の知っている言語の中にも IDLなどqiitaで全然記事が見つからない言語もあります。

プログラミング言語だけ比べるので、htmlxmlみたいなマークアップ言語や、cssみたいなスタイルシート言語などは含まれません。

rubyでタグのデータをcsvに保存する

rubyでは標準モジュールとしてopen-uriというスクレイピング用のモジュールがあるので、簡単にQiitaAPIからデータを取得できます。

csvの扱いも簡単にcsvモジュールが使えます。これも標準モジュールなので個別にインストールする必要がありません。

require "open-uri"
require "json"
require "csv"

gengo = %w!c c++ csharp cobol clojure delphi elm
erlang fortran golang haskell java javascript julia
kotlin lisp lua objective-c pascal perl php prolog
python r ruby rust scala swift typescript vb.net!

col = %w!id items_count followers_count!

CSV.open('qiitaprogramming.csv','w'){|csv|
  gengo.each{|gg|
    data = JSON.parse(open('https://qiita.com/api/v2/tags/'+gg).read)
    csv << col.map{|c|data[c]}
  }
}

こういうcsvファイルが出来ます。左の方が記事の数で、右の方がフォロワーの数です。

C,2632,21744
C++,5919,24875
C#,7427,23077
cobol,56,45
Clojure,619,550
Delphi,347,148
Elm,452,463
Erlang,524,446
Fortran,255,196
golang,2886,2025
Haskell,1904,9497
Java,12165,39527
JavaScript,26386,59733
Julia,570,620
Kotlin,2576,2243
lisp,267,358
Lua,452,320
Objective-C,3946,17766
Pascal,82,14
Perl,1469,12188
PHP,16169,37330
Prolog,207,96
Python,28671,55570
R,2727,1912
Ruby,21943,34065
Rust,1298,1527
Scala,2830,10363
Swift,11791,6603
TypeScript,3036,2325
VB.Net,359,322

pythonでデータを並べて棒グラフを描く

pythonにもスクレイピング用のモジュールがたくさんあります。ここではrequestsというモジュールを使います。

データを数によって並べるにはpandasでは一番やりやすいです。

グラフを描くにはmatplotlibが一番です。

どれでも標準モジュールではないからインストールする必要がありますが、anacondaとか使っていたら最初から含まれているはずです。

pip install requests pandas matplotlib

ちなみに、rubyにもdaruというpandasと似ているモジュールが存在します。https://github.com/SciRuby/daru/wiki/pandas-vs-daru

import requests
import matplotlib.pyplot as plt
import pandas as pd

lis_tagid = '''c c++ csharp cobol clojure delphi elm
erlang fortran golang haskell java javascript julia
kotlin lisp lua objective-c pascal perl php prolog
python r ruby rust scala swift typescript vb.net
'''.split()

gengo = []
n_follow = []
n_item = []
for tagid in lis_tagid:
    r = requests.get('https://qiita.com/api/v2/tags/'+tagid)
    r.raise_for_status()
    data = r.json()
    gengo.append(data['id'])
    n_follow.append(data['followers_count'])
    n_item.append(data['items_count'])

df = pd.DataFrame(index=gengo)
df['記事'] = n_item
df['フォロワー'] = n_follow
print(df)
y = range(len(df))

plt.figure(figsize=[6,6])
plt.gca(ylim=[min(y)-0.5,max(y)+0.5])
df.sort_values('フォロワー',inplace=True)
plt.yticks(y,['%s: %6s'%x for x in df['フォロワー'].iteritems()])
plt.barh(y,df['フォロワー'],color='#882244')
plt.title(u'フォロワㄧ',family='AppleGothic')
plt.tight_layout()

plt.figure(figsize=[6,6])
plt.gca(ylim=[min(y)-0.5,max(y)+0.5])
df.sort_values('記事',inplace=True)
plt.yticks(y,['%s: %6s'%x for x in df['記事'].iteritems()])
plt.barh(y,df['記事'],color='#337744')
plt.title(u'記事',family='AppleGothic')
plt.tight_layout()
plt.show()

結果

                記事  フォロワー
C             2632  21744
C++           5919  24875
C#            7427  23077
cobol           56     45
Clojure        619    550
Delphi         347    148
Elm            452    463
Erlang         524    446
Fortran        255    196
golang        2886   2025
Haskell       1904   9497
Java         12165  39527
JavaScript   26386  59733
Julia          570    620
Kotlin        2576   2243
lisp           267    358
Lua            452    320
Objective-C   3946  17766
Pascal          82     14
Perl          1469  12188
PHP          16169  37330
Prolog         207     96
Python       28671  55570
R             2727   1912
Ruby         21943  34065
Rust          1298   1527
Scala         2830  10363
Swift        11791   6603
TypeScript    3036   2325
VB.Net         359    322

Figure_1.png
Figure_2.png

纏め

結果から見ると、フォロワーの数はjavascriptの方が一番ですが、記事の数はpythonの方が一番です。

javascriptはウェブ開発に欠かせない言語ですし、データサイエンスや機械学習のおかげでこの数年の間にpythonはどんどん人気な言語になってきたようです。

二年前のこの記事を調べてみたら https://qiita.com/ty-edelweiss/items/b8172c2e22726bc08aeb
あの時pythonの記事はrubyよりも少なかったようです。

javaとphpとrubyもその次に人気のようです。

C言語などはフォロワーが多い割には記事が少ないです。

結果としてフォロワーと記事の数を見ると、この数年間のプログラミング言語の使う傾向をある程度示せるはずです。

編集: 2019年6月28日に、Rustを追加しました

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

選挙の演説の候補者の計算【ruby初心者】

はじめに

演説が終わるたび「他のそれぞれの立候補者の支持者から 1 人ずつ」および「誰も支持していない有権者から 1 人」支持者が増える。
その場合、最終結果で一番多い支持を集めた立候補者の番号を取得する。

実際のコード

#M は立候補者の人数を、N は有権者の人数を、K は演説が行われる回数
m,n,k = gets.split(" ").map &:to_i

#誰がどの順番で演説したかを表す整数 a_1, ..., a_K
a = readlines.map &:to_i

#立候補者の人数に応じて、支持者の人数を図れる配列を用紙
r=[]
m.times {r.push(0)}

#すべての演説が終わった後、最も支持者が多い立候補者の番号(複数ある場合は、すべて出力)
a.each do |i|
    #誰も支持していない人が、指示をする
    if n >0
        n -= 1
        r[i-1] += 1
    end
    #他の人を支持している人が、指示をする
    r.count.times do |t|
        if r[t] >0
            r[t] -= 1
            r[i-1] += 1
        end
    end
end

#最大数を返す
r.each_index do |t|
    if r[t] == r.max
        puts t+1
    end
end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

数あてゲームをrubyでつくる【初心者】

はじめに

特定の数よりも大きいか、小さいか、割り切れるかを複数回受け取り。1つの数字に絞られるまで条件を出していく、計算ゲーム。
数字は1〜100に制限。

入力例と出力例

入力例

4
/ 4
< 90
/ 6
> 77

出力例

84

実際のコード

#条件の入力合計回数
N = gets.chomp.to_i

#入力されたデータの取得
results = []
N.times do |timesCount|
    results.push(gets.chomp.split(" "))
end

#1~100の配列を用意しておく
i= [*(1..100)]

#条件に応じて、処理することを変える
results.each do |r|
    conpare,number = r.to_a
    if conpare == ">" 
        i = i.select {|item| item > number.to_i} #指定数値よりも大きい数字を選定
    elsif conpare == "<"
        i = i.select {|item| item < number.to_i} #指定数値よりも小さい数字を選定
    else
        i = i.select {|item| item % number.to_i == 0} #指定数値で割り切れる数字のみを選定
    end
end

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

RSpecを起動ようとしたら、「unknown command: Cannot call non W3C standard command while in W3C mode」と言われて怒られた

導入

以下の書籍を読みながら、RSpecについて学んでいます。

現場で使える Ruby on Rails 5速習実践ガイド

写経しながら、RSpecでテストコードを書いて、いざはじめてのRSpecと思って、
ワクワクしながらコマンドを叩くと、以下のエラーが出た。

Selenium::WebDriver::Error::UnknownCommandError:
       unknown command: Cannot call non W3C standard command while in W3C mode

Google Chromeとchromedriverのバージョンを最新の75にアップデートしたことで、W3CモードがデフォルトONになったみたい。

解決策

オプションに「w3c:false」を渡してやると、うまく解決が出来た。
自分の場合はオプションの設定方法が分からなくてハマったけど、何とかテストコードが動いて、
All Greenになった!

RSpec.configure do |config|

  config.before(:each, type: :system) do
    # 修正前
    driven_by :selenium_chrome_headless

    # 修正後
    caps = Selenium::WebDriver::Remote::Capabilities.chrome("chromeOptions" => {"w3c" => false})
    driven_by :selenium, using: :headless_chrome, screen_size: [1400, 1400], options: { desired_capabilities: caps }
  end

参考にしたURL

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

Elasticsearch aliasを用いた運用

背景

社内では既にElasticsearchを取り入れていましたが、運用においていくつか不便な点がありました。

既存index運用方法

  • ある用途に特化したindexを作成
  • 初期データをインポート
  • 追加発生 => インポート
  • 更新発生 => インポート
  • 削除発生 => 削除タスクの生成と実行

問題点

更新する場合は問題がありませんが、インポート対象が削除されていた場合は別途削除する為に削除リクエストをElasticsearchに送信する必要があります。

そのために発生したのが下記のようなもの。

  • 削除条件が増えるたびに専用の削除用rakeタスクができた。
  • インポートしてから削除するといった運用手順が生まれる。
  • 削除用rakeタスクのメンテ忘れによる、必要データが消えてしまう事件発生。
  • 不要なデータが残り続ける。

またindexの定義を更新または刷新したい時にAPI側はindex名を直指定しているため、容易に切り替えたり更新することができません。

新規index運用方法

新規運用方法といっても大したものではないですが、既存の問題を解決する為に alias を参照する用に変更して、裏に紐づくindexを切り替えるという方法を導入しました。

これにより、データを刷新したものに切り替えができるため削除用のタスクが不要になり、indexの定義更新等も容易になります。

下記を一つのタスクとすることで、シンプルな運用とする。

  1. index作成
  2. データのインポート
  3. alias切替
  4. 旧indexの削除

※更新の場合はインポートのみを実行

elastic/elasticsearch-rubyを利用してます。
※例なので、省略などを行なっておりそのまま実行はできません。

  def create
    # indexの定義を読み込む
    json = open(file_path) { |io| JSON.load(io) }

    # suffixにタイムスタンプを設定
    timestamp = Time.now.strftime('%Y%m%d%H%M%S')
    index_name = "#{alias_name}_#{timestamp}"

    # indexを作成
    client.indices.create index: index_name, body: json

    # 必要なデータのインポート
    client.bulk body: data

    # alias切り替え
    switch_alias(index: index_name)
  end

  def switch_alias(index:)
    # aliasに紐づいた古いindexを取得
    old_indices = client.indices.get_alias(name: alias_name).keys

    # alias削除リクエスト作成
    for_remove = old_indices.map { |old_index| { remove: { index: old_index, alias: alias_name } } }

    # alias追加リクエストを追加
    actions = for_remove + [{ add: { index: index, alias: alias_name } }]

    # リクエスト実行
    client.indices.update_aliases body: { actions: actions }

    # aliasに紐づいた古いindexを削除
    client.indices.delete index: old_indices
  end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

jQueryとsave時のエラー

はじめに

  • 条件を満たしているはずなのに新規登録時に登録に失敗しましたと出る
  • 登録失敗時のメッセージ「登録に失敗しました」が消えずにずっと表示されたままになっている。

この二つの問題解決にあたるが,いざ取り組むとあっさり解決した。途中まで書いてしまっていたので,一応投稿しておく。

内容はかなりしょぼいです。

JavaScript

「登録に失敗しました」が5秒で消えない。
とりあえず各ファイルの記述を見ていく。

users_controller.rb
class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      redirect_to root_path, success: '登録が完了しました'
    else
      flash.now[:danger] = "登録に失敗しました"
      render :new
    end
  end

  private
  def user_params
    params.require(:user).permit(:name, :email, :password, :password_confirmation)
  end
end
application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>Pictgram</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
     <% flash.each do |key, value| %>
       <div class="alert alert-<%= key %>" role="alert"><%= value %></div>
     <% end %>
     ~
     ~

     <%= yield %>

     <script>
       $(function(){
         $(".alert").fadeOut(5000);
       });
     </script>
  </body>
</html>
group :development do
  # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
  gem 'web-console', '>= 3.3.0'
  gem 'listen', '>= 3.0.5', '< 3.2'
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
  gem 'pry-rails'
  gem 'pry-doc'
  gem 'pry-byebug'
  gem 'pry-stack_explorer'
  gem 'jquery-rails'
  gem 'bcrypt'
  gem 'carrierwave'
end
application.js
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's
// vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require rails-ujs
//= require activestorage
//= require turbolinks
//= require bootstrap-sprockets
//= require jquery
//= require_tree .

各記述に加え,もちろんbundle installも行っている。

そこで少し調べたところ,Gemfileの記述に

gem 'jquery-ui-rails'

application.jsに

application.js
//= require jquery_ujs

を加えることで解決することがあるらしいので試してみるとあっさり解決。
Rubyのバージョンが古かったのかな?また今度調べてみる。

ROLLBACK

一番の問題はここ。
条件を満たしているはずの新規登録時にターミナルに以下のメッセージが出る。

Started POST "/users" for ::1 at 2019-06-26 17:51:29 +0900
Processing by UsersController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"VKkdJMhrlEzltFp
cD4OJLPN/LhgoyBHmIRj7R6Y+1Z/vn2QXJ60dLptQuvzdmYi/FBCRlSHsBljz/BpW9
PaQQg==", "user"=>{"name"=>"***", "email"=>"***", "passeword"=>"***", "password_confimation"=>"[FILTERED]"}, "commit"=>"登録"}
Unpermitted parameters: :passeword, :password_confimation
   (0.5ms)  BEGIN
  ↳ app/controllers/users_controller.rb:8
   (0.3ms)  ROLLBACK
  ↳ app/controllers/users_controller.rb:8
  Rendering users/new.html.erb within layouts/application
  Rendered users/new.html.erb within layouts/application (2.1ms)
  User Load (0.2ms)  SELECT  `users`.* FROM `users` WHERE `users`.
`id` IS NULL LIMIT 1
  ↳ app/controllers/concerns/common_actions.rb:5
Completed 200 OK in 69ms (Views: 58.3ms | ActiveRecord: 1.1ms)


Started GET "/users/new" for ::1 at 2019-06-26 17:54:52 +0900
Processing by UsersController#new as HTML
  Rendering users/new.html.erb within layouts/application
  Rendered users/new.html.erb within layouts/application (2.3ms)
  User Load (0.4ms)  SELECT  `users`.* FROM `users` WHERE `users`.
`id` IS NULL LIMIT 1
  ↳ app/controllers/concerns/common_actions.rb:5
Completed 200 OK in 83ms (Views: 80.0ms | ActiveRecord: 0.4ms)

ここで以下の記述に注目した

(0.3ms)  ROLLBACK
  ↳ app/controllers/users_controller.rb:8
  Rendering users/new.html.erb within layouts/application
  Rendered users/new.html.erb within layouts/application (2.1ms)

何かがロールバックしている。追っていくとまずはusers_controller.rbの8行目に何かあるよと。

users_controller.rb
# 8行目↓
if @user.save

じゃあこの処理はどこへ行ってるのかというとnew.html.erbである。このファイル内の記述を見ていく。

new.html.erb
<div class="users-new-wrapper">
  <div class="container">
    <div class="row">
      <div class="col-md-offset-4 col-md-4 users-new-container">
        <h1 class="text-center text-white">Sign up</h1>
        <%= form_for @user do |f| %>
          <div class="form-group">
            <%= f.label :name, class: 'text-white' %>
            <%= f.text_field :name, class: 'form-control' %>
          </div>
          <div class="form-group">
            <%= f.label :email, class: 'text-white' %>
            <%= f.text_field :email, class: 'form-control' %>
          </div>
          <div class="form-group">
            <%= f.label :password, class: 'text-white' %>
            <%= f.passeword_field :password, class: 'form-control' %>
          </div>
          <div class="form-group">
            <%= f.label :password_confirmation, class: 'text-white' %>
            <%= f.password_field :password_confimation, class: 'form-control' %>
          </div>

          <%= f.submit "登録", class: 'btn-block btn-white' %>
        <% end %>
        <%= link_to 'ログインはこちら', login_path, class: 'text-white' %>
      </div>
    </div>
  </div>
</div>

パッと見では問題がなさそう。
そこで調べてみると

users_controller.rb
if @user.save

if @user.save!

へ変更してみるとエラー個所がわかるよという記事を見つけた。
早速変更してrailsサーバーを再起動,新規登録を行ってみるとターミナルに新しい動きがあった。

ActiveRecord::RecordInvalid (Validation failed: Password can't be
blank, Password is too short (minimum is 8 characters), Password i
s invalid):

app/controllers/users_controller.rb:8:in `create'

なにやらパスワードがおかしいのかなと思う。下記の通りにValidationを設定しており,条件は満たしているはずなのに「空白はダメだよ(8文字以下になっているよ)」と怒られている。

user.rb
class User < ApplicationRecord
  validates :name, presence: true,
             length: { maximum: 15 }
  VALID_EMAIL_REGEX = /\A([\w+\-].?)+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/
  validates :email, presence: true,
             format: { with: VALID_EMAIL_REGEX }
  VALID_PASSWORD_REGEX = /\A(?=.*?[a-z])(?=.*?\d)[a-z\d]{8,32}+\z/i
  validates :password, presence: true,
             length: { minimum: 8, maximum: 32 },
             format: { with: VALID_PASSWORD_REGEX }

  has_secure_password

  has_many :topics
end

ここでは特になにもなさそうなのでpasswordの定義を行っているnew.html.erbへ戻って問題を確認する。

new.html.erb
        <%= form_for @user do |f| %>
          ~
          ~
          <div class="form-group">
            <%= f.label :password, class: 'text-white' %>
            <%= f.password_field :passeword, class: 'form-control' %>
          </div>
          <div class="form-group">
            <%= f.label :password_confirmation, class: 'text-white' %>
            <%= f.password_field :password_confimation, class: 'form-control' %>
          </div>

ここで間違いに気がつく。一箇所passwordがpassewordになっている。これを修正するとあっさり登録完了。問題は解決した。

おわりに

次回こそは
- 投稿する画像の制限
- 非ログイン時の投稿ボタンの非表示
を実装していく。

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

[Ruby on Rails]メールの送信結果をブラウザ上で確認する

メール送信結果をブラウザ上で確認する方法です。
letter_openerというgemを使います。
本番環境では実際に送信することになるので、開発環境でのみ確認できる状態を作ります。

環境

  • MacOS 10.14.5(18F132)
  • ruby 2.3.7p456
  • rails 5.2.3

手順

1. letter_openerをインストール

今回は開発環境でのみ確認できる状態を作るため、groupの設定をします。
すでにdevelopmentの設定が出来ている場合は、gem名のみを追記してください。

Gemfile
group :development do
  gem 'letter_opener_web'
end

追記したらコマンド

$ bundle install

2. 各種設定ファイルの編集

  • config/routes.rb
config/routes.rb
# 追記
if Rails.env.development?
  mount LetterOpenerWeb::Engine, at: "/letter_opener"
end
  • config/envirronments/development.rb
config/envirronments/development.rb
#追記
ActionMailer::Base.delivery_method = :letter_opener_web

#他にaction_mailerの設定をしている場合はコメントアウトする
#config.action_mailer.delivery_method = :smtp
#config.action_mailer.smtp_settings = {
  #省略
#}

3. ブラウザから確認する

$ rails sでサーバーを起動して、ブラウザでlocalhost:3000/letter_openerにアクセスします。
このような画面が表示されればOKです。
スクリーンショット 2019-06-27 16.49.38.png

4. メールを送信する

メールを送信する処理を実行します。

5. 再度ブラウザから確認する

ブラウザでlocalhost:3000/letter_openerにアクセスして、メールを確認します。
※deviseのパスワード再設定メールを送ってみました。
スクリーンショット 2019-06-27 17.45.17.png

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

投稿詳細ページを作成時のエラー

作ろうとしている物

・ブログ投稿サイト

困っていること

・ユーザーの投稿一覧画面から、タイトルをクリックすることで投稿詳細ページに飛ばしたい。が、できない。
スクリーンショット 2019-06-27 16.22.13.png
※投稿内容の文字についてはふざけていてごめんなさい。挙動を確認したかっただけなので、テキトーに書いておりました。

この画面で記事一覧のタイトルをクリックすると↓
Unable to autoload constant Blog_content, expected /Users/horiguchihiroki/blog/app/models/blog_content.rb to define it
Extracted source (around line #13):
11  def show
12    @blog = Blog_content.find_by(id: params[:id])
13  end
14
15

16
Rails.root: /Users/horiguchihiroki/blog

Application Trace | Framework Trace | Full Trace
app/controllers/blogs_controller.rb:13:in `show'

発生しているエラー(上記が見にくいのでマークダウンにしました)

Unable to autoload constant Blog_content, expected /Users/horiguchihiroki/blog/app/models/blog_content.rb to define it

@blog = Blog_contents.find_by(id: params[:id])
→コントローラのこの部分に赤線

コードレビュー

1、モデル名の確認
blog_content(app/model/以下に記載されているファイル名)

2、投稿一覧画面(app/blogs/index.html.erb)
飛ばす際に、paramsにクリックした投稿のid番号をパラメータとして付加し、コントローラのshowアクションに飛ばす。
※前提
投稿一覧画面では、インスタンス変数に@blogを用いています。

<div class="contents">
  <% @blog.each do |content|%>
    <p>
      <%= link_to(content.title_name, "/blogs/#{content.id}") %>
    </p>
  <% end %>
</div>

3、ルーティング(config/routes.rb)

Rails.application.routes.draw do
  root to: 'pages#index'
  resources :blogs
  devise_for :users, controllers:{
    regisrations: 'users/regisrations',
    sessions: 'users/sessions'
  }
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

補足でrake routesの結果↓

 Prefix Verb   URI Pattern                                                                              Controller#Action
                     root GET    /                                                                                        pages#index
                    blogs GET    /blogs(.:format)                                                                         blogs#index
                          POST   /blogs(.:format)                                                                         blogs#create
                 new_blog GET    /blogs/new(.:format)                                                                     blogs#new
                edit_blog GET    /blogs/:id/edit(.:format)                                                                blogs#edit
                     blog GET    /blogs/:id(.:format)                                                                     blogs#show
                          PATCH  /blogs/:id(.:format)                                                                     blogs#update
                          PUT    /blogs/:id(.:format)                                                                     blogs#update
                          DELETE /blogs/:id(.:format)                                                                     blogs#destroy
         new_user_session GET    /users/sign_in(.:format)                                                                 users/sessions#new
             user_session POST   /users/sign_in(.:format)                                                                 users/sessions#create
     destroy_user_session DELETE /users/sign_out(.:format)                                                                users/sessions#destroy
        new_user_password GET    /users/password/new(.:format)                                                            devise/passwords#new
       edit_user_password GET    /users/password/edit(.:format)                                                           devise/passwords#edit
            user_password PATCH  /users/password(.:format)                                                                devise/passwords#update
                          PUT    /users/password(.:format)                                                                devise/passwords#update
                          POST   /users/password(.:format)                                                                devise/passwords#create
 cancel_user_registration GET    /users/cancel(.:format)                                                                  devise/registrations#cancel
    new_user_registration GET    /users/sign_up(.:format)                                                                 devise/registrations#new
   edit_user_registration GET    /users/edit(.:format)                                                                    devise/registrations#edit
        user_registration PATCH  /users(.:format)                                                                         devise/registrations#update
                          PUT    /users(.:format)                                                                         devise/registrations#update
                          DELETE /users(.:format)                                                                         devise/registrations#destroy
                          POST   /users(.:format)                                                                         devise/registrations#create
       rails_service_blob GET    /rails/active_storage/blobs/:signed_id/*filename(.:format)                               active_storage/blobs#show
rails_blob_representation GET    /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show
       rails_disk_service GET    /rails/active_storage/disk/:encoded_key/*filename(.:format)                              active_storage/disk#show
update_rails_disk_service PUT    /rails/active_storage/disk/:encoded_token(.:format)                                      active_storage/disk#update
     rails_direct_uploads POST   /rails/active_storage/direct_uploads(.:format)                                           active_storage/direct_uploads#create

3、コントローラのshowアクション
paramsで付加したid番号から投稿を探し出して、インスタンス変数に代入する。(app/controller/blogs_controller)

class BlogsController < ApplicationController

  before_action :authenticate_user!
  #showを省いた
  before_action :set_blog, only: [:edit, :update, :destroy]



  def index
    @blog = current_user.blog_contents
  end
ーーーーーーーーーーーーーーーーーーーーーーーー
  def show
    @blog = Blog_contents.find_by(id: params[:id])
    →エラーはここのコードを指定して、赤線を出しています。
  end
ーーーーーーーーーーーーーーーーーーーーーーーー
  def new
    @blog = current_user.blog_contents.build
  end

  def edit
  end

  def create
    @blog = current_user.blog_contents.build(blog_params)

    respond_to do |format|
      if @blog.save
        format.html { redirect_to blogs_path, notice: 'Note was successfully created.' }
        format.json { render :show, status: :created, location: @blog }
      else
        format.html { render :new }
        format.json { render json: @blog.errors, status: :unprocessable_entity }
      end
    end
  end

  def update
    respond_to do |format|
      if @blog.update(note_params)
        format.html { redirect_to @blog, notice: 'Note was successfully updated.' }
        format.json { render :show, status: :ok, location: @blog }
      else
        format.html { render :edit }
        format.json { render json: @blog.errors, status: :unprocessable_entity }
      end
    end
  end

  def destroy
    @blog.destroy
    respond_to do |format|
      format.html { redirect_to notes_url, notice: 'Note was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    def set_blog
      @blog = current_user.blog_contents.find_by(id: params[:id])
      redirect_to root_path if @blog.nill?
    end

    def blog_params
      params.require(:blog_content).permit(:title_name, :content)
    end
end

5、投稿詳細画面
インスタンス変数に代入された投稿のタイトルと、中身を表示する。(app/views/show.html.erb)

<div class="content">
  <%= @blog.title_name %>
  <%= @blog.content %>
</div>

試したこと

発生しているエラー文をググって確認。
okerra.hatenablog.com/entry/2018/01/03/082902
https://ja.stackoverflow.com/questions/46942/ruby-on-rails-model-%E3%82%A8%E3%83%A9%E3%83%BC
https://teratail.com/questions/87201
https://teratail.com/questions/139281
https://teratail.com/questions/13505
https://ja.stackoverflow.com/questions/46942/ruby-on-rails-model-エラー
https://stackoverflow.com/questions/53486622/loaderror-unable-to-autoload-constant-board-game-expected-models-board-game-r

上記のサイトに書いてあることを以下のようにまとめてエラー処理を開始。
1、「モデルのファイル名とクラス名がサイトで指摘されているように間違っている」
→間違っていないことを確認。

2、「クラス名が呼ばれるはずの部分で、ファイル名の_(アンダーバー)が存在していることが原因?と疑って他のファイルを確認してみる」
→全てのファイルで検索をかけてみました。検索した文字(blog_content)。どこかで_(アンダーバー)を入れてたりしないのか?と探してみる。

上記のサイトに書いてあること以外で試してみたこと。
1、「そもそもモデルのファイルは読み込まれているのか?」
→一旦、モデルのファイルを消去してみる。そうするとモデルがないよ!という意味で「uninitialized constant BlogsController::Blog」が表示されるので、モデルを読み込もうとしている?ことは確認できたとする。
♦︎それなのにエラーが出るってことはやっぱり名前の部分がおかしいのか・・・?
♦︎でも名前部分に関するエラーは直したんだが・・・というループに陥る。

2、「同じコントローラ内で、別のアクションは機能しているか、問題ないのか?」
→ブログ新規投稿機能、一覧表示機能については問題なく動作する。ますますよくわからん。な状態です。

3、「そもそもautoloadとはなんぞや???と思い調べてみる」
https://railsguides.jp/autoloading_and_reloading_constants.html
よくわからないまま今に至ります。

適当に名前をいじってみたら詳細ページにはアクセスできた件

クラス名を、以下のように変更しました。

class Blog_content < ApplicationRecord
  belongs_to :user
end

そうすると詳細機能にはアクセスできるようになりました。
しかし、投稿一覧機能にはアクセスできなくなりました。しかも、調べたサイト的には正しくない?書き方になっています。

モデルのクラス名がRailsでどうやって呼ばれているのかを確認してみます。

ちょっと待てよ?と気づいた点

ご教授いただいてから気づいた、ちょっと待てよ?なところ。

クラス名を変更した(=コントローラで設定したBlogContentをBlog_contentsに変更した)らうまく行ったってことは、クラス名をコントローラで直接指定できるということじゃないか・・・?

至らな過ぎた勉強量

find_byメソッドに関して、使用するのはモデル名だけだと思い込んでおりました。
違いますね。モデルのクラス名またはインスタンスメソッドを指定してモデルのクラスを指定しているんですね。
まだまだ勉強足りないというか今までの開発って奇跡的にエラーが出てこないだけだったんだ。このエラーには出会ってよかった。

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

演算子の優先順位と意味

はじめに

用語と定義をしっかり覚える事が好きな自分用です。
演算子の優先順位とその意味を見やすくまとめようと思い投稿します。

優先順位

[高]   +(単項)  !  ~          !  否定演算子, ~a ビット演算子、aが1ならば0、またその逆
       **               ** 代数演算子, a**b aのb乗
       -(単項)                 
       *  /  %                   %  代数演算子, a%b aをbで割った時の余り
       +  -
       > >=  < <=
       <=> ==  === !=  =~  !~    <=> 宇宙船演算子, =~ 正規表現演算子 
       &&                        && 論理演算子, a && b aかつbが真ならば真
       ||                        || 論理演算子, a || b aまたはbが真ならば真
       ..  ...            .. 範囲演算子
       ?:(条件演算子)         ?= 条件演算子, a ? b : c aが真ならばbその他はc
       =
       not
[低]   and or

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

配列によるメソッドの可変長引数!

可変長引数とは???

個数に制限のない引数のこと!
自分で、定義するメソッドで可変長引数を使いたい場合は、引数名の手順に*をつけます!

sample.rb
def メソッド名(引数1,引数2,*可変長引数)
  #メソッドの処理
end

可変長引数は配列として受け取ることができます!

具体例を見ていきましょう!
次のコードは、引数として渡されたメニューの名前を、注文していくメソッドです。

sample.rb
def order(*food)
  puts "#{food.join('と')},お願いします!"
end

order('ハンバーガー') #ハンバーガー,お願いします!
order('ハンバーガー','ポテト') #ハンバーガーとポテト,お願いします!
order('ハンバーガー','ポテト','コーラ') #ハンバーガーとポテトとコーラ,お願いします!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

TECH ~Day5~

学習五日目を終えて、新たにまた新しい用語を学び始めました。
一旦レビュー管理アプリケーションを作る作業を終え、今回は「クラス」と「インスタンス」を学び始めました。
これを学びながら再びレビュー管理アプリケーションを作っていく作業を始めていきます。

学習内容
・クラスとインスタンス
・クラスの定義
・newメソッド
・クラスメソッド、インスタンスメソッド
・インスタンスの定義
・クラス変数、インスタンス変数

・クラスとインスタンス
クラス
とある種類のオブジェクトの共通の属性とメソッドをまとめて定義しておく型のようなもの。
(例)「人クラス」の場合
        性:名前、年齢、性別など
     メソッド:歩く、寝る、食べるなど

このような型を予め、定義しておくことによってこの方に沿った個別のオブジェクトを作ることができる。

インスタンス
クラスに基づいて生まれたオブジェクトをインスタンスと呼ぶ。
クラスが先。クラスからインスタンスが生まれるイメージ。
Rubyには予め定義されているクラスが存在する。
(例)
    配列オブジェクト:Arrayクラス
    数位オブジェクト:Integerクラス
  ハッシュオブジェクト:Hashクラス  など

・クラスの定義
書き方
 class クラス名
  !変数 / メソッドの定義
 end

(例)
 class Review

end
↑これはReviewクラスの定義
 もっともシンプルなクラスの定義の形

・newメソッド
定義したクラスからインスタンスを生成するには、「newメソッド」を使うとできる。
(例)
class Review
end

review = Review.new
この「あるクラス.new」というインスタンス生成のコードは、「クラスがメソッドを利用している」形である。

・クラスメソッド、インスタンスメソッド
クラスメソッド
 クラスが使用できる。クラスで共通の情報を使った処理に使用する。
 クラスの定義内で行う。

インスタンスメソッド
 インスタンスが使用できる。インスタンスごとの個別の情報(属性値)を使った処理に使用。

・インスタンスの定義
インスタンスメソッドの定義はインスタンスのクラスの「定義内」で行う。
書き方
class クラス名
def メソッド名
! 処理
end
end

・クラス変数、インスタンス変数
クラス変数
 クラス全体で使える変数。
 クラス内ではどこでも使えるため、クラスメソッド、インスタンスメソッドの両方で使える。
 クラスを通して、値が共通の情報に使用する。

インスタンス変数
 共通の属性としてインスタンスに定義できる変数。
 その値は個々のインスタンスによって別別に設定できる。

とりあえず五日目の学習内容は以上になります。
前回まで行っていた作業よりは理解しやすいないように感じました。引き続き学習に取り組みたいと思います。

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

【Ruby】配列の要素を追加・削除

【1章】はじめに

今回はRubyの配列におけるメソッドの中でも、要素を追加・削除するメソッドについてまとめました!
どれもよく使うメソッドなのでぜひ参考にしてください:woman::sunny:
では早速はじめます!

【2章】配列に要素を追加する

末尾に追加(<<)

array.rb
num = [1, 2, 3, 4]
num << 5
puts num
# 出力結果 ==> [1, 2, 3, 4, 5]

末尾に追加(push)

array.rb
num = [1, 2, 3, 4]
num.push(5)
puts num
# 出力結果 ==> [1, 2, 3, 4, 5]

num.push(6, 7)
puts num
# 出力結果 ==> [1, 2, 3, 4, 5, 6, 7]

こちらは上記のように複数一気に追加できます!

要素と要素の間に追加(insert)

array.rb
num = [1, 2, 3, 4]
num.insert(2,100)
#insert(何番目の要素に入れるか指定, 入れる要素)
#要素の番号は0から始まるので、今回は2を指定しているということは実際は3番目に100を追加するという意味
puts num
# 出力結果 ==> [1, 2, 100, 3, 4]


【3章】配列の要素を削除する

要素の番号を指定して削除(delete_at)

array.rb
num = [1, 2, 100, 3, 4]
num.delete_at(2)
#要素の番号は0から始まるので、今回は2を指定しているということは実際は3番目を削除するという意味
puts num
# 出力結果 ==> [1, 2, 3, 4]

要素の範囲を指定して削除(slice!)

array.rb
num = [1, 2, 3, 4, 5]
num.slice!(1, 3)
#slice!(最初に削除する要素の番号, ←で指定した番号から順番にいくつの要素を削除するか指定)
#今回は2番目の要素から3つ分削除
puts num
# 出力結果 ==> [1, 5]

要素名を指定して、該当する要素を全て削除(delete)

array.rb
animals = ["cat", "dog", "rabbit", "dog"]
animals.delete("dog")
puts animals
# 出力結果 ==> ["cat", "rabbit"]

配列の先頭から指定した数だけ削除(shift)

array.rb
num = [1, 2, 3, 4, 5]
num.shift(2)
#先頭から2つ分の要素を削除
puts num
# 出力結果 ==> [3, 4, 5]

【4章】さいごに

どうでしょうか?
配列の要素の追加や削除は自由自在に操れるようになっておいて損はありません!
ぜひ活用してみてください!
最後までご覧いただきありがとうございました:relaxed:

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

出力メソッドの使い分け

はじめに

初投稿です。備忘録としてまとめています。

print puts p ppメソッドの特性と出力結果を大まかに書いてみた。
参考:たのしいRuby

print

array = ["秋山","山本","馬場" ]

print "ロバート"
print 3
print array

結果

ロバート3["秋山", "山本", "馬場"]

printメソッドは改行、スペース無し。配列は展開されずに出力。

puts

array = ["秋山","山本","馬場" ]

puts "ロバート"
puts 3
puts array

結果

ロバート
3
秋山
山本
馬場

printメソッドと違い、一行ごとに改行が入り見やすくなる。

p

array = ["秋山","山本","馬場" ]

p "ロバート"
p 3
p array

結果

"ロバート"
3
["秋山", "山本", "馬場"]

文字列は""(ダブルクオーテーション)込みで出力される。文字列、数値、配列の型を分けて出力してくれる。

pとppの比較

require "pp"
array = [
    {title:"羅生門", auther:"芥川龍之介"},
    {title:"銀河鉄道の夜", auther:"宮沢賢治"},
    {title:"こころ", auther:"夏目漱石"}
]
p array
pp array

結果

[{:title=>"羅生門", :auther=>"芥川龍之介"}, {:title=>"銀河鉄道の夜", :auther=>"宮沢賢治"}, {:title=>"こころ", :auther=>"夏目漱石"}]

[{:title=>"羅生門", :auther=>"芥川龍之介"},
 {:title=>"銀河鉄道の夜", :auther=>"宮沢賢治"},
 {:title=>"こころ", :auther=>"夏目漱石"}]

ppメソッドはハッシュをキー毎に改行して見やすくしてくれる。
デバック時に便利

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

【Rails 備忘録】has_many先が存在しない場合、除外して格納する書き方。

はじめに

忘れてしまいがちなので備忘録。

条件

Projectモデルに、has_manyでParticipationモデルが関連付けされている。

createされたprojectにuserが参加アクションをすると、participationが該当のprojectにぶら下がる形でcreateされる。

なので、Projectのインスタンスであるprojectがparticipationを持っていない( @project.participations => [] )ということがありえる。

project.rb
class Project < ApplicationRecord
  has_many :participations



viewでparticipationを持っているprojectだけを表示したい。

やり方として一番簡単そうなのは、例えばcontrollerで
@projects = Project.where(user: current_user)
みたいな感じにして、viewテンプレートで

show.html.erb
<%= @projects.each do |project| %>
  <% if project.participations.present? %>
    <% project.name %>
  <% end %>
<% end %>

↑と書いてしまえばよいが、if文で毎回チェックさせるのもイマイチなので、
 controllerで@projectを格納するタイミングでparticipationがないものを除外させたい。

participationを持っているprojectだけを格納したい

答えを先に書くと、includeswhereを駆使して、

.includes(:participations).where(participations: Participation.all)
みたいな書き方をすればよい。

↓例:

participations_controller.rb
class ParticipationsController < ApplicationController

  def show
    @participation = Participation.find(params[:id])
    @projects = Project.where(client: current_client).where.not(status: "finished").
                  includes(:participations).where(participations: @participations)
  end

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

【Rails 備忘録】has_many先が存在しない場合に除外してインスタンス変数に格納する書き方。

はじめに

忘れてしまいがちなので備忘録。

条件

Projectモデルに、has_manyでParticipationモデルが関連付けされている。

createされたprojectにuserが参加アクションをすると、participationが該当のprojectにぶら下がる形でcreateされる。

なので、Projectのインスタンスであるprojectがparticipationを持っていない( @project.participations => [] )ということがありえる。

project.rb
class Project < ApplicationRecord
  has_many :participations



viewでparticipationを持っているprojectだけを表示したい。

やり方として一番簡単そうなのは、例えばcontrollerで
@projects = Project.where(user: current_user)
みたいな感じにして、viewテンプレートで

show.html.erb
<%= @projects.each do |project| %>
  <% if project.participations.present? %>
    <% project.name %>
  <% end %>
<% end %>

↑と書いてしまえばよいが、if文で毎回チェックさせるのもイマイチなので、
 controllerで@projectを格納するタイミングでparticipationがないものを除外させたい。

participationを持っているprojectだけを格納したい

答えを先に書くと、includeswhereを駆使して、

.includes(:participations).where(participations: Participation.all)
みたいな書き方をすればよい。

↓例:

participations_controller.rb
class ParticipationsController < ApplicationController

  def show
    @participation = Participation.find(params[:id])
    @participations = Participation.search_by_client(current_client)
    @projects = Project.where(client: current_client).where.not(status: "finished").
                  includes(:participations).where(participations: @participations)
  end

show.html.erb
<%= @projects.each do |project| %>
  <% project.name %>
<% end %>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails6 のちょい足しな新機能を試す42(multi-db db:migrate:status編)

はじめに

Rails 6 に追加されそうな新機能を試す第42段。 今回は、 multi-db db:migrate:status 編です。
Rails 6 では、 複数データベースに対応しているため、 db:migrate:status も複数データベースに対応しています。

Ruby 2.6.3, Rails 6.0.0.rc1 で確認しました。Rails 6.0.0.rc1 は gem install rails --prerelease でインストールできます。

$ rails --version
Rails 6.0.0.rc1

今回の準備

今回は、 Rails6 のちょい足しな新機能を試す35(複数データベース migration --database オプション編) をベースとして進めます。第35段まで終わっている状態を前提として話しを進めます。

一旦DBを作り直す

必要ないかも知れませんが、念のため、綺麗な状態から作業したいため、DBを作り直すことにしました。

bin/rails db:drop db:create db:migrate

カラムを追加するマイグレーションを作成する

これもまあ、必要ないと言えば必要ない気がするのですが、 backboneusers テーブル に email カラムを、
librarybooks テーブルに isbn カラムを追加するマイグレーションを作成します。

library 側に追加するためには、 --database (--db) オプションが必要です。

$ bin/rails g migration AddEmailToUser email
$ bin/rails g migration AddIsbnToBook isbn --database=library

db:migrate:status で確認する

db:migrate:status で確認すると、両方のデータベースのマイグレーションの状況が確認できます。

$ bin/rails db:migrate:status

database: backbone_development

 Status   Migration ID    Migration Name
 --------------------------------------------------
    up     20190608225735  Create user
   down    20190622004922  Add email to user


database: library_development

 Status   Migration ID    Migration Name
 --------------------------------------------------
    up     20190608225808  Create book
   down    20190622005021  Add isbn to book

どちらか1つのデータベースのマイグレーションの状態を知りたい場合は、 status に続けて :backbone:library を指定します。

$ bin/rails db:migrate:status:backbone

database: backbone_development

 Status   Migration ID    Migration Name
 --------------------------------------------------
    up     20190608225735  Create user
   down    20190622004922  Add email to user

$ bin/rails db:migrate:status:library

database: library_development

 Status   Migration ID    Migration Name
 --------------------------------------------------
    up     20190608225808  Create book
   down    20190622005021  Add isbn to book

試したソース

試したソースは以下にあります。
https://github.com/suketa/rails6_0_0rc1/tree/try042_multidb_migrate_status

注意

上のブランチで試す場合は、以下のように実行すれば、 bin/rails db:migrate:status の結果が同じになります。

$ bin/rails db:drop db:create
$ bin/rails db:migrate:backbone VERSION=20190608225735
$ bin/rails db:migrate:library VERSION=20190608225808

参考情報

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

SVG画像を3x3で並べる

原子構造をベクター画像で描くツールを作りました。
https://github.com/NuNoKehai/xyzb2image
が、このプログラムだと1ユニットセル分しか描かないので、そのままでは見た目がイマイチ。
NFB.png
もともとイラストレータで3x3に並べていましたが、イラストレーターって画像の位置合わせがイマイチ苦手ですね。だからと言って描画ユニットセルを増やすオプションはつけたくない。
と言うことで、ベクトル画像を3x3するrubyスクリプトを書きました。

svg3x3.rb
require 'rubygems'
require 'cairo'
require 'rsvg2'

def read_suffix(filename)

  index_period=filename.rindex(".")
  suffix=filename[index_period+1..filename.size-1]

  return suffix

end

def cairo_imagesurface_general(filename_image, width, height)

  suffix_image=read_suffix(filename_image)

  if suffix_image.casecmp("pdf")==0
     surface = Cairo::PDFSurface.new(filename_image, width, height)
  elsif suffix_image.casecmp("svg")==0
    surface = Cairo::SVGSurface.new(filename_image, width, height)
  else
    format = Cairo::FORMAT_ARGB32
    surface = Cairo::ImageSurface.new(format, width, height)
  end

  return surface

end

def context_finish_general(filename_image,context)

  suffix_image=read_suffix(filename_image)

  if suffix_image.casecmp("pdf")==0 || suffix_image.casecmp("svg")==0
    context.target.finish
  elsif suffix_image.casecmp("png")==0
    context.target.write_to_png(filename_image)
  end

end

filename_in=ARGV[0]
filename_out=ARGV[1]

handle_in = RSVG::Handle.new_from_file(filename_in)
width_in=handle_in.dimensions.width
height_in=handle_in.dimensions.height

surface_out = cairo_imagesurface_general(filename_out, width_in*3, height_in*3)
context_out = Cairo::Context.new(surface_out)
context_out.render_rsvg_handle(handle_in)
context_out.translate(width_in,0)
context_out.render_rsvg_handle(handle_in)
context_out.translate(width_in,0)
context_out.render_rsvg_handle(handle_in)
context_out.translate(-2*width_in,height_in)
context_out.render_rsvg_handle(handle_in)
context_out.translate(width_in,0)
context_out.render_rsvg_handle(handle_in)
context_out.translate(width_in,0)
context_out.render_rsvg_handle(handle_in)
context_out.translate(-2*width_in,height_in)
context_out.render_rsvg_handle(handle_in)
context_out.translate(width_in,0)
context_out.render_rsvg_handle(handle_in)
context_out.translate(width_in,0)
context_out.render_rsvg_handle(handle_in)
context_finish_general(filename_out,context_out)

このスクリプトを動作させるためには rubygem の cairo と rsvg2 が必要です。
最初に定義した3つの関数は出力ファイルの拡張子の汎用性を増やすためです。
やってることはユーザー空間の原点をずらして入力画像を描画してるだけ。

使い方です。
ruby svg3x3.rb input.svg output.pdf
のように、入力ファイル名と出力ファイル名をargumentで指定。
入力ファイルはsvg形式である必要があります。

結果。
NFB_3x3.png
できました。
後は、画像出力的にいらない部分をイラストレーターのクリッピングマスク等で切り取ってしまえばOK。

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

YAMLとSlimで論文リストを作る

概要

以下のようなYAMLファイル(publication.yaml)を食わせて、

-
  title: How to write web sites with slim
  author: R. Robota, T. Tanaka
  journal: Ruby Journal
  year: 2010
  volume: 10
  page: 1-7
  arxiv: 1234.56789

-
  title: Using YAML file with slim
  author: R. Robota
  journal: Journal of Slim
  year: 2018
  volume: 8
  page: 1275

-
  title: This is a sample file for Slim and YAML
  author: S. Yaml, T. XML and R. Robota
  journal: J. Yaml. Phys.
  year: 2017
  volume: 3
  page: 12-18
  arxiv: 1908.01234

以下のようなHTMLを吐くSlimテンプレートのサンプルです。

image.png

ソースは以下においておきます。

github.com/kaityo256/yamlslim

何をしたいか

論文リストとかそうですが、とりあえずなんかリストがあり、それを静的なHTMLにしたい、ということはよくあります。とりあえず論文リストはJSONかYAMLで用意されてるとしましょう。これをHTMLにしたい。さほど更新頻度も高くないので、CMSとかデータベースを導入するほどでもない、でもHTMLを直書きするのは嫌だ、という気持ち、わかっていただけますよね?

で、どうしましょう。

そういう用途では、とりあえずPHPでゴリゴリ書いちゃう、という方法が考えられます。PHPはそれが本職の言語なので、わりとまっとうな気がします。

もしくはJSON+JavaScriptというのもありな気がしますね。JSのテンプレートエンジンは豊富にあるので、好きなのを使ってなんとかする、というのが最近では良い気がします。

ですが、個人的に母国語がRubyということもあって、Rubyスクリプトの埋め込みができる軽量テンプレートエンジン、Slimを使うことにします。

Slimとは

Slimは軽量テンプレート言語です。おそらくRuby on Railsと一緒に使われることが多いと思いますが、ローカルでHTMLを吐くのにも使えます。日本語の公式ドキュメントがわかりやすいので、使うのは簡単だと思います。

Rubyとgemが入っていればSlimのインストールは簡単です。

$ sudo gem install slim

このあと、

$ slimrb -v

とかやってバージョン情報が出てきたらインストールされています。

例えば、

test.slim
doctype html
html
  head
    title My first Slim
  body
    h1 This is test
    h2 Hello Slim

こんなファイルを作って、

$ slimrb test.slim

とslimに食わせると、

<!DOCTYPE html><html><head><title>My first Slim</title></head><body><h1>This is test</h1><h2>Hello Slim</h2></body></html>

と、HTMLにしてくれます。-pオプションをつけると人間が読みやすい形にしてくれます。

$ slimrb -p test.slim
<!DOCTYPE html>
<html>
  <head>
    <title>My first Slim</title>
  </head>
  <body>
    <h1>
      This is test
    </h1>
    <h2>
      Hello Slim
    </h2>
  </body>
</html>

さて、Slimの特徴は、Rubyスクリプトをそのまま埋め込めることです。ハイフン-のあとにRubyスクリプトが書けます。また、=を使って、HTML要素にRubyの実行結果を代入できます。たとえば変数aを定義して、h1に突っ込むにはこうします。

test2.slim
doctype html
html
  head
    title My first Slim
  body
    - a = "Hello"
    h1 = a
test2.html
<!DOCTYPE html>
<html>
  <head>
    <title>My first Slim</title>
  </head>
  <body>
    <h1>
      Hello
    </h1>
  </body>
</html>

上記のようにaに代入された値を、h1要素に突っ込むことができました。

また、配列などに対してeachを使い、その要素を列挙できます。

test3.slim
doctype html
html
  head
    title My first Slim
  body
    ol
      - ["Dog", "Cat", "Cow"].each do |animal|
        li = animal

これをslimrbに食わせるとこんなHTMLになります。

test3.html
<!DOCTYPE html>
<html>
  <head>
    <title>My first Slim</title>
  </head>
  <body>
    <ol>
      <li>
        Dog
      </li>
      <li>
        Cat
      </li>
      <li>
        Cow
      </li>
    </ol>
  </body>
</html>

image.png

リストとeachのからみは直感的なので、特に苦労することはないと思います。

YAMLから論文リストを作る

まずはナイーブに作る

ではいよいよYAMLで書かれた論文リストからHTMLにしましょう。とりあえず

  • タイトル
  • 著者
  • ジャーナル情報
  • (もしあれば)arXivへのリンク

を出力することにします。

RubyはYAMLを読み込めば、それがそのままハッシュとして使えるので、先程のeachの例を参考にすれば簡単に書けます。

test1.slim
doctype html
html
  - require 'yaml'
  head
    title Publication List
  body
    h1 Publication List
    ol
      - YAML.load_file("publication.yaml").each do |d|
        li :dl
          dt = d["title"]
          dd == "#{d["journal"]}, <strong>#{d["volume"]}</strong>, #{d["page"]} (#{d["year"]})"
          dd = d["author"]
          - if d.has_key? "arxiv"
            dd == "<a href=\"https://arxiv.org/abs/#{d["arxiv"]}\">arXiv:#{d["arxiv"]}</a>"

事前にrequire 'yaml'しておき、YAML.load_file("publication.yaml")でYAMLファイルをロードして、eachでそれぞれのアイテムを表示します。if文も使えるので、特に難しいことはありませんが、テンプレートとしてはかなり読みづらいので、少し修正しましょう。

ハッシュアクセスをプロパティっぽくする

いちいちd["title"]とか書くより、d.titleと書きたいものです。Hashieを使えばできるっぽいのですが、なぜかローカルで動かなかったので、Hashクラスにメソッドを追加してしまいましょう。

myhash.rb
class Hash
  def method_missing(method, *args)
    key = method.to_s
    if self.has_key? key
      self[key]
    else
      false
    end
  end
def

存在しないメソッドを読んだら、そのメソッド名のキーがあればその値を、そうでなければfalseを返す関数を作ってやります。これにより、slimファイルはこんな感じになります。yamlをrequireした後に自分で作ったmyhash.rbをrequireしています。

test2.slim
doctype html
html
  - require 'yaml'
  - require './myhash.rb'
  head
    title Publication List
  body
    h1 Publication List
    ol
      - YAML.load_file("publication.yaml").each do |d|
        li :dl
          dt = d.title
          dd == "#{d.journal}, <strong>#{d.volume}</strong>, #{d.page} (#{d.year})"
          dd = d.author
          - if d.arxiv
            dd == "<a href=\"https://arxiv.org/abs/#{d.arxiv}\">arXiv:#{d.arxiv}</a>"

生のハッシュっぽさが消えて、少し読みやすくなりました。

そうそう、Slimでは普通にHTMLタグを使うとエスケープされてしまいます。それを防ぐためには=ではなく==を使います。

もう少しすっきりさせる

少し読みやすくなったものの、まだ"#{d.journal}, <strong>#{d.volume}</strong>, #{d.page} (#{d.year})"みたいなのがあって嫌です。これもmyhash.rbに逃がしてしまいましょう。

myhash.rb
class Hash
  def journal_ref
    "#{journal}, <strong>#{volume}</strong>, #{page} (#{year})"
  end

  def arxiv_ref
    "<a href=\"https://arxiv.org/abs/#{arxiv}\">arXiv:#{arxiv}</a>"
  end
def

これで、slimファイルはこんな感じになります。

test3.slim
doctype html
html
  - require 'yaml'
  - require './myhash.rb'
  head
    title Publication List
  body
    h1 Publication List
    ol
      - YAML.load_file("publication.yaml").each do |d|
        li :dl
          dt = d.title
          dd == d.journal_ref
          dd = d.author
          - if d.arxiv
            dd == d.arxiv_ref

だいぶすっきりしましたね。

まとめ

軽量テンプレート言語Slimを使って、ローカルでYAMLファイルから論文リストを作ってみました。知っている人には簡単なのでしょうが、そのものずばりのサンプルがなくてちょっと苦労したのでここに公開しておきます。

ずいぶん昔、文献リストをXMLで管理していたことがありました。その時に「RubyとYAMLでやれば楽じゃない?」と言われたのですが、当時はPerlを使っていてRubyを使えなかったのと、将来XSLTを使う予定があったので、その時はXMLを選びました。でもXSLTは(僕には)難易度が高く、そのうち第一言語がRubyになったので、結局Ruby+YAMLでなんかすることが多くなりました(YAMLで履歴書とか)。

Slimは簡単で、かつRubyが埋め込めるので、HTMLを手書きに近い管理をしていて、かつRubyistな人(つまり私のような人)にはお勧めです。

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

【Rails】Action Mailer でメール送信機能をつくる

概要

Action Mailerを使ってメールの送信機能をつくります:speech_balloon:
今回は管理者がユーザーからのお問い合わせに対して、管理者画面から返事をすると、
ユーザーにメールで送信される機能を実装していきます。

学習メモとして記録 :writing_hand_tone4:

参考

(1)RAILS GUIDES: Action Mailer の基礎
(2)【Ruby on Rails】メール送信の実装手順(ActionMailer)とはまったエラーなど
(3)Railsでメール自動配信機能をつくるまでの道程
(4)Rails の ActionMailer でメール送信処理
(5)RailsのAction Mailerでメール送信

Action Mailerとは

Ruby on Rails に組み込まれているメール送信機能のこと。
Action Mailer を使うと、Ruby on Rails からメールを送信してくれます :envelope:

・メールマガジンの一斉送信
・ウェブサイトに会員登録した時のthank youメール
・お問い合わせフォームの記入内容が管理者にメールでも送信される

のような時にアプリケーションからメールを送信する機能と解釈してます。
アプリケーションのメーラークラスやビューからメールを送信することができる便利な機能です!

導入手順

1. メイラーを生成

railsコマンド(rails generate)で生成します。 ContactMailer は任意クラス名。
今回はお問い合わせ関係のメール送信機能を作成したいためContactMailerです。

terminal.生成
$ rails generate mailer ContactMailer

terminal.結果
Running via Spring preloader in process 1893
   create  app/mailers/contact_mailer.rb
   invoke  erb
   create    app/views/contact_mailer
   invoke  rspec
   create    spec/mailers/contact_mailer_spec.rb
   create    spec/mailers/previews/contact_mailer_preview.rb

無事に生成されましたね :v_tone3:

2. サーバーを設定

メールを送信するときは、送信するサーバーが必要。と言うことで、
config/environments/development.rbにメール送信設定を記述します。
今回はg-mailを使う記載方法です。

development.rb
Rails.application.configure do
  #--- 中略 ---#
  config.action_mailer.raise_delivery_errors = true
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    port:                 465,
    address:              'smtp.gmail.com',
    domain:               'gmail.com',
    user_name:            '<YOUR EMAIL ADDRESS>',
    password:             '<YOUR EMAIL PASSWORD>',
    authentication:       'login',
    enable_starttls_auto: true
  }
end

上から順々に見ていきます。
ここでは、config.action_mailerというパラメーターに色んなオプションを指定してます。

1行目 raise_delivery_errors
メールの送信に失敗した時にエラーを出すかどうか (出したいので true)

2行目 delivery_method
メールの送信方法。 デフォルトで :smtd なので気にする必要もないのですが、
わたしみたいに「なにそれ!?」ってなった方は以下の引用を読んでみてください。

「SMTP」とは「Simple Mail Transfer Protocol(シンプル・メール・トランスファー・プロトコル)」の略で、あえて>訳せば「簡単なメールの送信の手順」というところだろうか。お約束ごとと考えてもいい。

あなたがメールを書き、宛先のアドレスを入力して「送信」アイコンをクリックする。このとき、あなたのスマホやパソコン>は、この「SMTP」のお約束ごとに従って、あなたが契約しているメールサーバーと、こんなやり取りをするのである。
「メールを送るよ〜」「ええで!」「宛先は〇◯だよ」「りょ」「本文はかくかくしかじかだよ」「受け取ったで!」――とまぁそんな具合。

出典: メール設定で最初につまずく「SMTP」「POP」「IMAP」。その意味&設定方法は?

3行目 smtp_settings
smtpの詳細設定って感じです。

  1. port => SMTPサーバーのポート番号
  2. address => SMTPサーバーのホスト名
  3. domain => HELOドメイン
  4. user_name => メール送信に使用するgmailのアカウント
  5. password => メール送信に使用するgmailのパスワード
  6. authentication => 認証方法
  7. enable_starttls_auto => メールの送信にTLS認証を使用するか

GmailのSTMPサーバーの設定 :gear:

上記に関しては以下を参考に設定しました。
『GmailのSMTPをメールクライアントに設定する方法』の部分を参照しました。
GmailのSMTPサーバーを使ってGmail以外からメールを送信する方法

3. メーラーを編集

メーラーってRailsのコントローラーと似てるんですね。
「アクション」と呼ばれるメソッドがあり、メールの内容をつくるのにビューを使います。

生成直後は、以下のような application_mailer.rb

app/mailer/application_mailer.rb
class ApplicationMailer < ActionMailer::Base
  default from: 'from@example.com'
  layout 'mailer'
end

空のメーラー

app/mailer/contact_mailer.rb
class ContactMailer < ApplicationMailer
end

があるはずです。

application_mailerには全メーラー共通の設定を、
sample_mailerにはメーラー個別の設定をします。

application_mailerを編集します

app/mailer/contact_mailer.rb
class ApplicationMailer < ActionMailer::Base
  default from:    "管理人 <from@example.com>",
  layout 'mailer'
end

共通の処理・設定を記述する場合にはdefaultメソッドを使用します。

プロパティ 役割
to 送信先の指定
cc 一斉送信先の指定
bcc 非表示送信先の指定
from メールの送信元名
subject メールタイトル
date メールの送信日時
reply_to 返信用アドレスの指定

などが指定できます。

contact_mailer.rb を編集します

今回は管理者の返信がユーザーのe-mailに届くようにします。
なのでメソッドをsend_when_admin_replyと定義しました。

app/mailer/contact_mailer.rb
class ContactMailer < ApplicationMailer

  def send_when_admin_reply(user, contact) #メソッドに対して引数を設定
    @user = user #ユーザー情報
    @answer = contact.title #返信内容
    mail to: user.email, subject: '【サイト名】 お問い合わせありがとうございます'
  end

end

個別の設定にはmailメソッドを使用します。
send_when_replyedメソッドを呼び出す時に渡されるユーザーの情報から、
emailアドレスだけを取り出してメールの送信先としてします。

mailメソッドが呼び出されると、メール本文が記載されているビューが読み込まれます。
インスタンス変数(@xxx)でメーラービューに値を渡してあげたいので、インスタンス変数を用意してる感じです。

次は、そのメールの本文を作成していきます :keyboard:

4. メールの本文を作成する(メーラービューの作成)

app/views/contact_mailerディレクトリ下にファイルを2つ作成します。

1つはHTMLフォーマット、もう一つはテキストメール。
顧客によってはHTMLフォーマットのメールを受け取ることができない / 受け取りたくない人もいるので、テキストメールも作成しておくのが最善です。

HTMLファイルの作成

views/contact_mailer/send_when_admin_reply.html.erb
  <h2><%= @user.name %> 様</h2>
 <p>この度は、お問い合わせありがとうございました。<br>
 以下でご質問の回答となっておりますでしょうか。</p>

  <p><%= @reply %></p>

  <p>今後とも XXX をよろしくお願いいたします。</p>

テキストファイルの作成

views/contact_mailer/send_when_admin_replyd.text.erb
  ===============================
  <%= @user.name %> 様
  ===============================

  この度は、お問い合わせありがとうございました。
 以下でご質問の回答となっておりますでしょうか。

  <%= @reply %>

  今後とも XXX をよろしくお願いいたします。

5. 実際に処理を走らせるアクションにメール送信処理をさせる

メールの設定を記述しただけではメールは送信できません。
メーラー(ここではapplication_mailer.rb / contact_mailer.rb)は各コントローラーのアクションからの呼び出しによって起動します。

管理者がアプリケーション管理画面フォームより返信を送信し、その内容をメールでユーザーに送信します。
実際に処理を走らせるアクションはadmin/contacts_controller.rbとなります。

app/controllers/contacts_controller.rb
class Admin::ContactsController < Admin::ApplicationController
  def update
   contact = @contact #contact_mailer.rbの引数を指定
   user = contact.user #contact_mailer.rbの引数を指定
   ContactMailer.send_when_admin_reply(user, contact).deliver
  end
end

例えば、ユーザーが新規アカウント登録をしてメールを送信する場合は、

app/controllers/users_controller.rb
class UsersController < ApplicationController
  before_action :set_user

  def create
    if @user.save #ユーザーのインスタンスが新しく生成されて保存されたら
      NotificationMailer.send_when_signup(@user).deliver #確認メールを送信
      redirect_to @user
    else
      render 'new'
    end
  end
end

createアクションに処理を走らせることになります。

わたしのアプリケーションでは、DBの設計上
ユーザーが問い合わせをした時点で、Contactsテーブルの中に、
1つレコードが準備されていて、その中に'返信'というカラムが用意されています。

なので、updateアクションを使って
すでにあるレコードの中に管理者の返信のデータだけを更新してあげる形になります:sunflower:

6. テストしてみる

以上でメーラーができるはずです・・!
実際にアプリケーションを動かしてみて、メールを受信できたら成功 :ok_hand_tone3:

以上、学習メモでした :hatched_chick::writing_hand_tone4:

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

神経衰弱ゲームをrubyでつくる【ruby初心者】

はじめに

神経衰弱ゲームを作ってみる。

実際のコード

#縦の数、横の数、プレイヤーの数を受け取る
h,w,n = gets.chomp.split(" ").to_a

#カードの並びを行列で入れる変数を宣言
cards = []

#高さの数だけ、受け取りを繰り返す。
h.to_i.times do
    array = gets.chomp.split(" ").map &:to_i
    cards.push(array)
end

#プレイヤーの数だけ、スコアの配列を用意する
score=[]
n.to_i.times do
    score.push(0)
end

#実行回数
l = gets.chomp.to_i

#ターンの宣言
turn = 0


#ゲームの開始
l.times do
    #実行回数分、めくったカードを配列で受け取る。
    array = gets.chomp.split(" ").map &:to_i

    #受け取った配列を、各回の行列に代入する。
    a_1,b_1,a_2,b_2 =array.to_a

    #めくったカードの指定をする
    first  = cards[a_1 -1][b_1 -1]
    second = cards[a_2 -1][b_2 -1]

    #カードが一致だったらスコアをあげる
    if first == second
        score[turn] += 2

    #一致しなければ、次のターンに移る。
    else
        turn += 1
        if score.count <= turn
            turn=0
        end
    end
end

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

文字列が合うまで、何回配列を動かせばいいか計算するプログラム 【ruby初心者】

はじめに

工場などで、向きを調整するプログラム。

実際のコード

#入力の受付
input_line = gets.chomp.split(" ")

#文字を配列になおす
collect = input_line[1].split("") #答えの文字列
testings = input_line[2].split("") #受け取った文字列

#試行回数をカウントする変数
a = 0


testings.each do
    #もしも文字列が一致すれば、終了して試行回数を表示する
    if collect == testings
        puts a
        break
    else
    #文字列が一致しなければ、配列を入れ替える
        t = testings[0]
        testings.shift()
        testings.push(t)
    end
    a += 1
end

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

算数のあなぬけ問題の回答作成プログラム

はじめに

a + b = c
または
a - b = c
などで、a,b,cのいずれかが、虫食いになっている場合の、回答作成方法

実際のコード

#入力は、 a + b = x や、 a - x = c などの形で来る
#入力の受付
input_line = gets.chomp.split(" ")


#それぞれ変数に代入する
#これ一行でも表せる。 a,enzan, b, equal, c = input_line.to_a
a = input_line[0]
b = input_line[2]
c = input_line[4]

enzan = input_line[1]


#"x"の位置と、"enzan"の値によって、出力する計算式を変える。
if a == "x"
    if enzan == "+"
        puts c.to_i - b.to_i
    else
        puts c.to_i + b.to_i
    end
elsif b == "x"
    if enzan == "+"
        puts c.to_i - a.to_i
    else
        puts a.to_i - c.to_i
    end
else
    if enzan == "+"
        puts a.to_i + b.to_i
    else
        puts a.to_i - b.to_i
    end
end

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

[Array]Ruby

Hello world.

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

エレベーターの距離を計算するプログラム【ruby初心者】

はじめに

エレベーターの距離計算機能。絶対値などの計算の練習メモ。

作る機能

①移動データを、配列として取得する
②数値の初期設定
③距離を絶対値で計算する

実際のコード

#入力データを、配列として取得する
input_lines = readlines.map &:to_i

#現状の階数と、距離の初期設定
floor_now = 1
distance = 0


input_lines.each do |a|
    #距離の絶対値で計算をする
    if (a - floor_now) >0
        distance += a - floor_now
    else
        distance -= a - floor_now
    end
    #距離計算後に、階数を更新する
    floor_now = a
end

puts distance

絶対値の計算をもっと簡単に

コメントでのアドバイスを反映。5行で書いていた下記の絶対値の計算。

#距離の絶対値で計算をする
if (a - floor_now) >0
    distance += a - floor_now
else
    distance -= a - floor_now
end

下記のように1行で書き直すことが可能。

#距離の絶対値で計算をする

distance += (a - floor_now).abs
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

gem impressionist を使ってユニークpv数を計測【Rails】

ruby 2.5.1
rails 5.2.1

はじめに

impressionistを使ってpv数を計測しようと思い、色々調べながら実装するもなかなかユニークpv数が取得できずに苦戦していました。結果的にreadme(https://github.com/charlotte-ruby/impressionist) を見て解決したので、その記録として残しておきます。最初からreadme見ればよかった。。。

導入方法

Gemfile
gem 'impressionist'
$ bundle install

次にpvを保存するテーブルを作成します。

$ rails g impressionist

このようになっていれば大丈夫です。

Running via Spring preloader in process 40810
      invoke  active_record
      create    db/migrate/20190626153731_create_impressions_table.rb
      create  config/initializers/impression.rb

migrateします。

$ rails db:migrate

Model

今回はQ&Aサイトの質問ページのpv数を取得したいためQestionモデルに以下のように記載します。

question.rb
class Question < ApplicationRecord
  is_impressionable
end

Controllers

セッションハッシュでフィルタリングされたモデルからユニークpv数を取得します。IPで判別すると同じIPを使用する訪問者を計測できないのでセッションハッシュで判別するのがいいっぽいです。

question_controller.rb
class QuestionsController < ApplicationController
  impressionist unique: [:session_hash]

  def show
    @question = Question.find(params[:id])
    impressionist(@question, nil, unique: [:session_hash])
  end
end

Views

show.html.erb
<%= @question.impressionist_count %>

スクリーンショット 2019-06-27 2.08.00.png

更新してもテーブルのレコードや表示されるpv数が増えていなければ完璧!

他の記事を参考したけど全然できなかったのでreadmeを読んだのですが、これが足りなかったようです。
impressionist unique: [:session_hash]

公式リファレンスを見る習慣をつけます。

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

Ruby on Rails

Ruby on Rails

  • Ruby on Railsの記事編集中
abc abc abafdafd
afdfdsafdsaf dfdsfsdfa fdafdafa
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む