20201017のRubyに関する記事は15件です。

本日の学習まとめ ユーザー管理機能実装にて

はじめに

 今回は完全に自分用で覚えておきたいことを雑多に書き連ねている。

正規表現

 

PASSWORD_REGEX = /\A(?=.*?[A-z])(?=.*?[\d])[A-z\d]+\z/i.freeze # 半角英数混合1字以上
ZENKAKU_REGEX = /\A[ぁ-んァ-ン一-龥]+\z/.freeze # 全角ひらカタ漢字
KANA_REGEX = /\A[ァ-ヶー-]+\z/.freeze # 全角カナ

freezeは変数が変わらないようにするため。

バリデーションのオプションをまとめる

with_options presence: true do
 validates #オプションをつける 
end

エラーメッセージを表示させる

foem_withの中でrenderメソッドでファイルを呼び出す。そのとき、devise配下のファイルであるように記述をする。

<%= form_with model: @user, url: user_registration_path', local: true do |f| %>
  <%= render 'devise/shared/error_messages', model: f.object %>
_error_messages.html.erb
<% if model.errors.any? %>
  <div id="error_explanation">
    <h2>
      <%= I18n.t("errors.messages.not_saved",
                 count: model.errors.count,
                 resource: model.class.model_name.human.downcase)
       %>
    </h2>
    <ul>
      <%= model.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
    </ul>
  </div>
<% end %>

modelを呼び出すように記述する。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

3桁の整数からそれぞれの桁の数字を取り出す

表題の通り、
3桁の整数から百の位・十の位・一の位の数字を取り出す方法のアウトプットです。

百の位

整数を100で割ったものを、更に10で割った計算結果の余りが百の位。

num = 345
result_100 = (num / 100) % 10
puts result_100
# => 3

普通に(num / 100)をすると3.45になるけれども、
Rubyの場合は、整数 / 整数 = 整数(小数点以下切り捨て)になるので
(num / 100)は3になる。

十の位

整数を10で割ったものを、更に10で割った計算結果の余りが十の位。

num = 345
result_10 = (num / 10) % 10
puts result_10
# => 4

(num / 10)が34で、34を10で割ると余りが4。

一の位

整数を10で割った計算結果の余りが一の位。

num = 345
result_1 = num % 10
puts result_1
# => 5

おまけ

もし4桁の数字で千の位の数字を取り出したいときは
(num / 1000) % 10となる。百の位、十の位、一の位は上記と同じ求め方。

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

Rubyの正規表現について(メタ文字、キャプチャ、関連メソッド)

はじめに

 正規表現を覚え始めたため、その使い方について備忘も兼ねて記述します。

サンプルコード

以下のようなプロフィールがあるとします。

text = <<TEXT
生年月日:1234年5月6日生まれ
郵便番号:789-1111
TEXT

生年月日から数字のみを抽出したい場合

(\d+)(\d+)(\d+)
#=> 1234,5,6 が抽出される。
#=>下は年月日の漢字もマッチしてしまう。
\d+\d+\d+
#=>1234年5月6日

正規表現のメタ文字の意味

\d ・・・ 半角数字(桁は問わない)
+  ・・・ 直前の文字やパターンが1回以上連続している
() ・・・ 内部でマッチした文字列をキャプチャまたはグループ化
年,月,日 ・・・メタ文字ではなく、ただの文字列

郵便番号の間にハイフン"-"を除きたい場合

p text[/\d{3}-\d{4}/].gsub('-','')
#=>7891111

正規表現のメタ文字やメソッドの意味

/(正規表現)/ ・・・正規表現オブジェクトは/で囲んで作成する(「Rubyにおける正規表現リテラル」という)
[]・・・文字列から正規表現にマッチした部分を抜き出すStringクラスのメソッド。エイリアスメソッドは、sliceメソッド。
{3},{4}・・・直前の文字(この場合は\d)が、{}で囲んだ数だけ連続する
- ・・・メタ文字ではなく、ただのハイフン。(ハイフンは、記述の仕方によっては「文字の範囲」を表す場合もあるため注意)
gsub('第1引数','第2引数')・・・第1引数にマッチした文字列を第2引数の文字列で置き換える。上記の場合、文字列"-"を""(削除を意味する)に変換している。
なお、sliceメソッドやgsubメソッドには、それぞれ「破壊的メソッド(※)」が用意されている。
(※)呼び出したオブジェクトの状態を変更してしまうメソッド。末尾に"!"を付ける。

正規表現のテストができるツール

正規表現は、メタ文字を駆使するため試行錯誤できるツールがを使うと、視覚的に確認できます。
reg_exp.png

https://rubular.com/

終わりに

文字列の検索や置換で威力を発揮する正規表現。
近いうちに使いこなしたいと思い、まずは初歩的な学習内容を記述しました。
ここまで読んでくださり、ありがとうございました。

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

Rails if文とunlessの混合条件式の作成

最終課題に向けて調整を行いました。
その際に、条件式をifとunlessの両方を使用するという特殊なパターンに
チャレンジしてみました。備忘録として投稿させて頂きます。

今回はhamlにて記述しています。

sample.rb
#viewファイルにて

.item-show-page__link-btn
        -if @item.buyers.present?
          %p SOLD OUT
        -else
          - unless user_signed_in? && @item.user_id == current_user.id
            = link_to purchase_item_path(@item.id), class: "item-show-page__link" do
              購入画面へ
          - else
            %p 出品者は購入できません

メソッドの中身
@item 出品情報が入っています。
buyers 購入した履歴のメソッドになります。

解説

if〜else
もし購入した履歴のIDが存在したらSOLD OUTを表示

unless~else
if文のelseの中に入れ子として格納しています。そこからunlessの条件式を入れています。
もし出品した商品とユーザーIDが一致しない場合は購入画面に遷移するリンクを出現。
そうでない場合は「出品者は購入できません」と出現させる。

以上となります。

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

Rails6 + Bootswatch / Honoka の導入

Bootstrap 様には大変お世話になっております。デザインセンスのない私でも簡単にそこそこ見れるサイトを作ることができます。ありがとうございます。

しかしながら「いかにも ...」な感じがしてきたので、Rails に Bootswatch の導入してみました。また「日本語が美しい」と評判の Honoka の導入にもチャレンジしてみました。

環境

Ruby 2.7.2
Rails 6.0.3.4
Yarn 1.22.10
Webpack をインストールして、トップページが表示できる状態になっていること

トップページの作成

Bootstrap を導入する準備として、トップページを作成します。

app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>VoiceOrigami</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

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

  <body>
  <%= render 'layouts/header' %>
    <div class="container">
      <%= yield %>
    </div>
  <%= render 'layouts/footer' %>
  </body>
</html>
app/views/static_pages/top.html.erb
<!--<div class="container">-->
  <div class="jumbotron m-3">
    <h1 class="display-4 red">ようこそ! テストアプリへ</h1>
    <hr class="my-4">
    <p>Ruby on Rails + Bootstrap のテンプレートです</p>
    <button type="button" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#exampleModal">
      <i class="far fa-window-maximize"></i>
      モーダルを開く
    </button>
  </div>
  <!-- Modal -->
  <div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
    <div class="modal-dialog" role="document">
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title" id="exampleModalLabel">モーダルタイトル</h5>
          <button type="button" class="close" data-dismiss="modal" aria-label="Close">
            <span aria-hidden="true">&times;</span>
          </button>
        </div>
        <div class="modal-body">
          ありがとう
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-secondary" data-dismiss="modal">とじる</button>
        </div>
      </div>
    </div>
  </div>
<!--</div>-->

app/views/layouts/_header.html.erb
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
  <a class="navbar-brand" href="#">Navbar</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>

  <div class="collapse navbar-collapse" id="navbarSupportedContent">
    <ul class="navbar-nav mr-auto">
      <li class="nav-item active">
        <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Link</a>
      </li>
      <li class="nav-item dropdown">
        <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
          Dropdown
        </a>
        <div class="dropdown-menu" aria-labelledby="navbarDropdown">
          <a class="dropdown-item" href="#">Action</a>
          <a class="dropdown-item" href="#">Another action</a>
          <div class="dropdown-divider"></div>
          <a class="dropdown-item" href="#">Something else here</a>
        </div>
      </li>
      <li class="nav-item">
        <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
      </li>
    </ul>
    <form class="form-inline my-2 my-lg-0">
      <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
      <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
    </form>
  </div>
</nav>
app/views/footer.html.erb
<footer class="footer">
  <div class="container">
    <p class="text-muted">Place sticky footer content here.</p>
  </div>
</footer>
app/assets/stylesheets/cutstom.scss
 .red { // custom.scss が読み込まれているかチェックするため
   font-size: 2rem;
   color: red;
 }


 /* Sticky footer styles
-------------------------------------------------- */
 html {
   position: relative;
   min-height: 100%;
 }
 body {
   /* Margin bottom by footer height */
   margin-bottom: 60px;
 }
 .footer {
   position: absolute;
   bottom: 0;
   width: 100%;
   /* Set the fixed height of the footer here */
   height: 60px;
   background-color: #f5f5f5;
 }


 /* Custom page CSS
 -------------------------------------------------- */
 /* Not required for template or sticky footer method. */

 .container {
   width: auto;
   max-width: 680px;
   padding: 0 15px;
 }
 .container .text-muted {
   margin: 20px 0;
 }

Bootstrap が導入されていないため、崩れて表示されます。

snap_1810.png

Bootstrap の導入

Yarn で Bootstrap をインストールします。

$ yarn add bootstrap@4.5.2 jquery popper.js

bootstrap を適用します。

app/javascripts/packs/application.js
require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")
+ import 'bootstrap'
+ import '../src/application.scss'
app/javascripts/src/application.scss
@import '~bootstrap/scss/bootstrap';

ここで stylesheet_link_tag を削除してしまうと、app/assets/stylesheets/cutstom.scss が読み込まれなくなるので注意してください。2行コードを追記します。

app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>VoiceOrigami</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
+    <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
+    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>

Heroku にアップロードした後も Bootstrap を適用するためにコードを追記

config/webpack/environment.js
const { environment } = require('@rails/webpacker')

    const webpack = require('webpack')

    environment.plugins.append('Provide', new webpack.ProvidePlugin({
        $: 'jquery/src/jquery',
        jQuery: 'jquery/src/jquery',
        Popper: ['popper.js', 'default']
    }))
module.exports = environment

以上で、Bootstrap4 が導入できました。

snap_1811.png

Bootswatch の導入

Bootswatch は Bootstrap 互換のフリーテーマ集です。

https://bootswatch.com/

導入方法は、先ほどの手順とほぼ同じです。

Yarn で Bootstrap をインストールします。

$ yarn add bootswatch@4.5.2

bootswatch (Minty) を適用します。

app/javascripts/src/application.scss
+ @import '~bootswatch/dist/minty/variables';
@import '~bootstrap/scss/bootstrap';
+ @import '~bootswatch/dist/minty/bootswatch';

これで Bootswatch の導入は完了です。見慣れた Bootstrap が素敵に変身しましたね。Minty 以外のテーマも試してみてください。

snap_1812.png

Honoka

コツが掴めたので、今度は Honoka を導入してみましょう。日本語が美しい Bootstrap テーマです。

https://honokak.osaka/

Yarn でインストール

$ yarn add bootstrap-honoka

Honoka を適用します。(残念ながら Minty と同時に適用はできませんでした)

app/javascripts/src/application.scss
//@import '~bootswatch/dist/minty/variables';
//@import '~bootstrap/scss/bootstrap';
//@import '~bootswatch/dist/minty/bootswatch';
@import '~bootstrap-honoka/dist/css/bootstrap';

Navibar のリンクの下に白線が付くなど、微妙に変化していることが確認できました。

snap_1813.png

Webpack の仕組みがよく理解できず苦労しましたが、Bootswatch / Honoka の導入が完了しました。どなたかのお役に立てれば幸いです。

参照

https://qiita.com/taKassi/items/56172d140d7208230e32

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

JavaScriptのライブラリJQueryでイベント発火Ajax(非同期通信の場合)

前提

  • 非同期通信
  • Ruby.Rails
  • 送信フォームが送信(sendボタン押すイベント発火)されたらカラーのパネルが追加させる実装を行うことを例にする。
  • <例>発火すると右上に選択した色が非同期通信で表示される。

スクリーンショット 2020-10-16 15.09.31.png

 

イベントが発火した際にあることが実行されるようにする

①何をきっかけに(イベントは何?)
②イベントきっかけにどんなとこを実行するか

この2つを考えながらコードを考える。

「今回は送信ボタンを押したら(イベント)カラーパネルが追加されることが実行される」

①送信ボタンを押すということは「フォームが送信された時」だと考える。
②イベントをきっかけにカラーパネルが表示されるにはいくつかの工程が必要だと考える。
 →Ajaxを使用(データ関連の引き渡し)
 →HTMLで変化後の見た目(イベント発火をきっかけに起こる一部見た目の変化)

①何をきっかけに(イベント発火は何?)

きっかけ:フォームの送信

フォームにイベントをセットする。
「フォームのボタンを押した時」というのを記述。

###.js(JavaScriptファイル)
$(function(){
  $(*****).on(*****, function(){

  })
})

フォームのクラスを $( )に入れて、
「.on」は押すという意味を加える。
「on( , 」のon( の後には何を押すのかをいれる。
今回は'submit'ボタンを入れた。

<記述例>
$(function(){
  $('.js-form').on('submit', function(){

  })
})

また、console.logを用いてイベント発火しているか確認もしてみてください。
空いている行に記述して送信ボタンを押すことで確認できます。
<例>console.log("テスト")
などカッコに入れてみてください。
スクリーンショット 2020-10-16 16.15.58.png
できていない時はエラーが出るはずです。

  

次に、フォーム送信を停止

今のままだとデフォルトの設定として、
フォーム送信と共に画面が今まで非同期通信ではない画面遷移(画面移動)してしまう。
通常設定は阻止する必要がある。
非同期通信を行うために、preventDefault()を使用する。

###.js(JavaScriptファイル)
  $(*****).on(*****, function(e){
    e.preventDefault()

  })
})

この際も真ん中の空いている行にconsole.logを入れてエラーが出てないか確認してみてください。
 
 
 

②イベントきっかけにどんなとこを実行するか

  • Ajaxを使用(データ関連の引き渡し)
  • HTMLで変化後の見た目(イベント発火をきっかけに起こる一部見た目の変化)

Ajaxを使用(データ関連の引き渡し)

この後必要になる基本のコード
先ほどのコードに 「$.ajax({」から追加しています。

javascripts/###.js
$(function(){
  $(*****).on(*****, function(e){
    e.preventDefault()
    $.ajax({
      url: 取得したリクエストURL,  //同期通信でいう『パス』
      type: 'POST',  //同期通信でいう『HTTPメソッド』
      data: 取得したFormData,  
      dataType: 'json',
      processData: false,
      contentType: false
    })
  })
})

↑この記述を行っても遷移先のviewファイル(〇〇.json.jbuilder)を作成していないとエラーが出ます。
 

ここからは送信フィームをイベントとした例を元にみていきます。

<例>
$(function() {
  $('.js-form').on('submit', function(e) {
    e.preventDefault();
    // ここから下追加記述
    let formData = new FormData(this);
    let url = $(this).attr('action');
    $.ajax({
      url: url,
      type: "POST",
      data: formData,
      dataType: 'json',
      processData: false,
      contentType: false
    })
  });
});

 

「フォームに入力された値を受け取れるようにする記述をする」
FormData

フォームのデータの送信に使用。
new FormData(フォーム要素)とすることでFormDataを作成。
今回の場合オブジェクトの引数はthis。
イベントで設定したfunction内でthisを利用した場合は、
イベントが発生したノード要素を指す。
今回の場合は、js-formというクラスがついたフォームの情報を取得している。
IDなどでも取得できる。

<例>のFormDataについて
   let formData = new FormData(this);

 

attrメソッド

引数に指定した属性の値を取得することができる。

<例>のattrメソッドとurlについて
let url = $(this).attr('action');

例では引数に'action'を指定しているので(ここではthis)from要素のaction属性の値が取得できる。
スクリーンショット 2020-10-16 19.16.40.png

「/songs/3/songcolors」このパスがactionから取れてurlに入れられてる。
そのurlがAjaxのurlに関わってくるのだと思います。
  
 
 

「$.ajax」の部分に非同期通信に必要なオプションを設定
<例>$.ajaxからの記述
    $.ajax({
      url: url,
      type: "POST",
      data: formData,
      dataType: 'json',
      processData: false,
      contentType: false
    })
オプション 内容
type HTTP通信の種類を記述する。通信方法は、GETとPOSTの2種類。
url リクエストを送信する先のURLを記述する。遷移先、パス
data サーバに送信する値を記述する。今回はデータを格納したものが入る。
dataType サーバから返されるデータの型を指定する。
processData デフォルトではtrue。dataに指定したオブジェクトをクエリ文字列(例: msg.txt?b1=%E3%81%8B&b2=%E3%81%8D )に変換する役割。
contentType サーバにデータのファイル形式を伝えるヘッダ。FormDataをつかってフォームの情報を取得した時には必ずfalseにする。さらに詳しくはこちら

  
 
 

 

HTMLで変化後の見た目(イベント発火をきっかけに起こる一部見た目の変化)

非同期通信の結果(ブラウザの見た目としての変化)として返ってくるデータは、done(function(data) { 処理 })の関数の引数で受け取る。
doneメソッドを使う。

また、doneメソッドで受け取った引数( )を元に「function buildHTML〜」の後からHTMLを組み立てる。

javascripts/###.js
$(function(){
  //ここから下5行追記
  function buildHTML(***jsファイル名***){
    let html = `<*******>
                </*******>`//`から`の間にHTMLが入る。
    return html;
  }
  $(*****).on(*****, function(e){
    e.preventDefault()
    let formData = new FormData(this); //フォームからデータをとってくる場合この一文を必要とする。
    let url = $(this).attr('action'); //フォームのアクションに指定されたものが必要になる場合この一文が必要。
    $.ajax({
      url: 取得したリクエストURL,  //同期通信でいう『パス』
      type: 'POST',  //同期通信でいう『HTTPメソッド』
      data: 取得したFormData,  
      dataType: 'json',
      processData: false,
      contentType: false
    })
   //ここから以下追記
    .done(function(data){
      let html = buildHTML(data);
      $('.***ボタンのクラス***').prop('disabled', false) //一度押すと押せなくなる送信ボタンを連続で押せるようにしている
      $('***元のHTMLに追加したい場所を指定***').prepend(html);//.prepend指定した要素の最初に、引数で指定した内容を追加
    })
  })
})
doneメソッド

.when( ) は先に実行したい処理。
.done( ) は後で実行したい処理。
のように処理をいつしたいか設定できます。
 

$('.ボタンのクラス').prop('disabled', false)

disabled属性をfalseにする記述でsubmitボタンが押せないのをfalseで解除する。
 

function buildHTMLL( ){let html = `<****></****>return html;}

doneメソッドで受け取った引数( )を元にHTMLを組み立てる。
HTMLの組み立てはつど全く違っているのでここに記述しておりませんが自分のコードを例に置いておいきます。

<例>HTMLの箇所をピックアップしたもの
  function buildHTML(songcolor){
    let html =
      `<li class="color-box" style="background-color:${songcolor.color}"></li>`
    return html;
  };

検証ツールで追加したいHTMLを見てみるととてもわかりやすいのと、
データベースの情報を表示する際は${}を使用すること、
ここに持ってくる情報は対応するviweに作った.json.jbuilderに設定したことを思い出すとわかりやすいかも。

 

prependメソッド

元のHTMLのどの部分に追加するのかクラスなどを指定して決める。
指定した要素(クラスなど)の最初に足すことができる。
そのほかにも最後に足したりするメソッドなども存在する。
 

 

 

このように様々なメソッドを使用することで、
テキストボックス内をイベント後に空にしたり設定することができる。

 
 
 
 
 

イベント発火により実行することが実装できたら…

その実行ができなかった場合を想定する

javascripts/###.js
$(function(){
  function buildHTML(******){
    let html = `<*******>
                </*******>`
    return html;
  }
  $(*****).on(*****, function(e){
    e.preventDefault()
    let formData = new FormData(this);
    let url = $(this).attr('action');
    $.ajax({
      url: 取得したリクエストURL,
      type: 'POST',
      data: FormData,  
      dataType: 'json',
      processData: false,
      contentType: false
    })
    .done(function(data){
      let html = buildHTML(data);
      $('.******').prop('disabled', false)
      $('******').prepend(html);
    })
   //ここから以下追記
    .fail(function(){
      alert('error');
   });
  })
})
failメソッド

サーバーエラーの場合にdoneではなくfailが呼び出される。
 

alertメソッド

アラートが呼び出される。('****')の中身の文字がアラートで表示される。
 
 
 
 
 
 
以上です!
これで非同期通信の作業は最後です。
ほかにも様々な設定ができるのでこればかりではないのですが、
一旦ここで終わります。
 
 
 
 

最後にひとこと

ここまでまとめてみて、
一つ一つの記述の意味がより理解できました。
ただ、実際に新たに自分のオリジナルのアプリを開発したからというのも合わさっていたことが
今回の理解につながったのだと思います。

新たな疑問点や課題

  • 非同期通信をする際の手順を自分で思い出しながら実装できるかの不安
  • doneメソッドの引数であるHTMLの組み立て
  • done後の様々な記述
  • Ajax後の設定が他で応用できるのか
  • 非同期通信以外にJavaScriptでできることがあるがどんな仕組みなのか    

理解が深まっていても実装で使用できるか
また、まだまだ理解が追いついていない部分を学習していきたいと思います。
 
 
初めてJSみた時はこんなの読めないと思っていましたが
今は少し見慣れてパーツごとに見れるようになったのが嬉しいです。
 
 
 
 
最後まで読んでくださってありがとうございました!
ではまた〜

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

JavaScriptのライブラリJQueryでイベント発火Ajax(非同期通信を実装する場合)

前提

  • 非同期通信
  • Ruby.Rails
  • 送信フォームが送信(sendボタン押すイベント発火)されたらカラーのパネルが追加させる実装を行うことを例にする。
  • <例>発火すると右上に選択した色が非同期通信で表示される。

スクリーンショット 2020-10-16 15.09.31.png

 

イベントが発火した際にあることが実行されるようにする

①何をきっかけに(イベントは何?)
②イベントきっかけにどんなとこを実行するか

この2つを考えながらコードを考える。

「今回は送信ボタンを押したら(イベント)カラーパネルが追加されることが実行される」

①送信ボタンを押すということは「フォームが送信された時」だと考える。
②イベントをきっかけにカラーパネルが表示されるにはいくつかの工程が必要だと考える。
 →Ajaxを使用(データ関連の引き渡し)
 →HTMLで変化後の見た目(イベント発火をきっかけに起こる一部見た目の変化)

①何をきっかけに(イベント発火は何?)

きっかけ:フォームの送信

「フォームのボタンを押した時」というのを記述。

###.js(JavaScriptファイル)
$(function(){
  $(*****).on(*****, function(){

  })
})

フォームに設定したのクラス名を $( )に入れて、
「.on」で押すという意味を加える。
「on( , 」のon( の後には何を押すのかをいれる。
今回は'submit'ボタンを入れた。

<記述例>
$(function(){
  $('.js-form').on('submit', function(){

  })
})

また、console.logを用いてイベント発火しているか確認もしてみてください。
空いている行に記述して送信ボタンを押すことで確認できます。
<例>console.log("テスト")
などカッコに入れてみてください。
スクリーンショット 2020-10-16 16.15.58.png
できていない時は検証のコンソールでエラーが出るはずです。

  

次に、デフォルト設定の方のフォーム送信を停止

今のままだとデフォルトの設定として、
フォーム送信と共に画面が今まで通り(非同期通信ではなく)画面遷移(画面移動)してしまう。
通常設定は阻止する必要がある。
非同期通信を行うために、preventDefault()を使用する。

###.js(JavaScriptファイル)
  $(*****).on(*****, function(e){
    e.preventDefault()

  })
})

この際も真ん中の空いている行にconsole.logを入れてエラーが出てないか確認してみてください。
 
 
 

②イベントきっかけにどんなとこを実行するか

  • Ajaxを使用(データ関連の引き渡し)
  • HTMLで変化後の見た目(イベント発火をきっかけに起こる一部見た目の変化)

Ajaxを使用(データ関連の引き渡し)

この後必要になる基本のコード
先ほどのコードに 「$.ajax({」から追加しています。

javascripts/###.js
$(function(){
  $(*****).on(*****, function(e){
    e.preventDefault()
    // ここから下追加記述
    $.ajax({
      url: 取得したリクエストURL,  //同期通信でいう『パス』
      type: 'POST',  //同期通信でいう『HTTPメソッド』
      data: 取得したFormData,  
      dataType: 'json',
      processData: false,
      contentType: false
    })
  })
})

↑この記述を行っても遷移先のviewファイル(〇〇.json.jbuilder)を作成していないとエラーが出ます。
 

ここからは送信フィームをイベントとした例を元にみていきます。

<例>
$(function() {
  $('.js-form').on('submit', function(e) {
    e.preventDefault();
    // ここから下追加記述
    let formData = new FormData(this);
    let url = $(this).attr('action');
    $.ajax({
      url: url,
      type: "POST",
      data: formData,
      dataType: 'json',
      processData: false,
      contentType: false
    })
  });
});

 

「フォームに入力された値を受け取れるようにする記述をする」
FormData

フォームのデータの送信に使用。
new FormData(フォーム要素)とすることでFormDataを作成。
今回の場合オブジェクトの引数はthis。
イベントで設定したfunction内でthisを利用した場合は、
イベントが発生したノード要素を指す。
今回の場合は、js-formというクラスがついたフォームの情報を取得している。
IDなどでも取得できる。

<例>のFormDataについて
   let formData = new FormData(this);

 

attrメソッド

引数に指定した属性の値を取得することができる。

<例>のattrメソッドとurlについて
let url = $(this).attr('action');

例では引数に'action'を指定しているので(ここではthis)from要素のaction属性の値が取得できる。
スクリーンショット 2020-10-16 19.16.40.png

「/songs/3/songcolors」このパスがactionから取れてurlに入れられてる。
そのurlがAjaxのurlに関わってくるのだと思います。
  
 
 

「$.ajax」の部分に非同期通信に必要なオプションを設定
<例>$.ajaxからの記述
    $.ajax({
      url: url,
      type: "POST",
      data: formData,
      dataType: 'json',
      processData: false,
      contentType: false
    })
オプション 内容
type HTTP通信の種類を記述する。通信方法は、GETとPOSTの2種類。
url リクエストを送信する先のURLを記述する。遷移先、パス
data サーバに送信する値を記述する。今回はデータを格納したものが入る。
dataType サーバから返されるデータの型を指定する。
processData デフォルトではtrue。dataに指定したオブジェクトをクエリ文字列(例: msg.txt?b1=%E3%81%8B&b2=%E3%81%8D )に変換する役割。
contentType サーバにデータのファイル形式を伝えるヘッダ。FormDataをつかってフォームの情報を取得した時には必ずfalseにする。さらに詳しくはこちら

  
 
 

 

HTMLで変化後の見た目(イベント発火をきっかけに起こる一部見た目の変化)

非同期通信の結果(ブラウザの見た目としての変化)として返ってくるデータは、done(function(data) { 処理 })の関数の引数で受け取る。
doneメソッドを使う。

また、doneメソッドで受け取った引数( )を元に「function buildHTML〜」の後からHTMLを組み立てる。

javascripts/###.js
$(function(){
  //ここから下5行追記
  function buildHTML(***jsファイル名***){
    let html = `<*******>
                </*******>`//`から`の間にHTMLが入る。
    return html;
  }
  $(*****).on(*****, function(e){
    e.preventDefault()
    let formData = new FormData(this); //フォームからデータをとってくる場合この一文を必要とする。
    let url = $(this).attr('action'); //フォームのアクションに指定されたものが必要になる場合この一文が必要。
    $.ajax({
      url: 取得したリクエストURL,  //同期通信でいう『パス』
      type: 'POST',  //同期通信でいう『HTTPメソッド』
      data: 取得したFormData,  
      dataType: 'json',
      processData: false,
      contentType: false
    })
   //ここから以下追記
    .done(function(data){
      let html = buildHTML(data);
      $('.***ボタンのクラス***').prop('disabled', false) //一度押すと押せなくなる送信ボタンを連続で押せるようにしている
      $('***元のHTMLに追加したい場所を指定***').prepend(html);//.prepend指定した要素の最初に、引数で指定した内容を追加
    })
  })
})
doneメソッド

.when( ) は先に実行したい処理。
.done( ) は後で実行したい処理。
のように処理をいつしたいか設定できます。
 

$('.ボタンのクラス').prop('disabled', false)

disabled属性をfalseにする記述でsubmitボタンが押せないのをfalseで解除する。
 

function buildHTMLL( ){let html = `<****></****>return html;}

doneメソッドで受け取った引数( )を元にHTMLを組み立てる。
HTMLの組み立てはつど全く違っているのでここに記述しておりませんが自分のコードを例に置いておいきます。

<例>HTMLの箇所をピックアップしたもの
  function buildHTML(songcolor){
    let html =
      `<li class="color-box" style="background-color:${songcolor.color}"></li>`
    return html;
  };

検証ツールで追加したいHTMLを見てみるととてもわかりやすいのと、
データベースの情報を表示する際は${}を使用すること、
ここに持ってくる情報は対応するviweに作った.json.jbuilderに設定したことを思い出すとわかりやすいかも。

 

prependメソッド

元のHTMLのどの部分に追加するのかクラスなどを指定して決める。
指定した要素(クラスなど)の最初に足すことができる。
そのほかにも最後に足したりするメソッドなども存在する。
 

 

 

このように様々なメソッドを使用することで、
テキストボックス内をイベント後に空にしたり設定することができる。

 
 
 
 
 

イベント発火により実行することが実装できたら…

その実行ができなかった場合を想定する

javascripts/###.js
$(function(){
  function buildHTML(******){
    let html = `<*******>
                </*******>`
    return html;
  }
  $(*****).on(*****, function(e){
    e.preventDefault()
    let formData = new FormData(this);
    let url = $(this).attr('action');
    $.ajax({
      url: 取得したリクエストURL,
      type: 'POST',
      data: FormData,  
      dataType: 'json',
      processData: false,
      contentType: false
    })
    .done(function(data){
      let html = buildHTML(data);
      $('.******').prop('disabled', false)
      $('******').prepend(html);
    })
   //ここから以下追記
    .fail(function(){
      alert('error');
   });
  })
})
failメソッド

サーバーエラーの場合にdoneではなくfailが呼び出される。
 

alertメソッド

アラートが呼び出される。('****')の中身の文字がアラートで表示される。
 
 
 
 
 
 
以上です!
これで非同期通信の作業は最後です。
ほかにも様々な設定ができるのでこればかりではないのですが、
一旦ここで終わります。
 
 
 
 

最後にひとこと

ここまでまとめてみて、
一つ一つの記述の意味がより理解できました。
ただ、実際に新たに自分のオリジナルのアプリを開発したからというのも合わさって
今回の理解につながったのだと思います。

新たな疑問点や課題

  • 非同期通信をする際の手順を自分で思い出しながら実装できるかの不安
  • doneメソッドの引数であるHTMLの組み立て
  • done後の様々な記述
  • Ajax後の設定が他で応用できるのか
  • 非同期通信以外にJavaScriptでできることがあるがどんな仕組みなのか    

理解が深まっていても実装で使用できるか
また、まだまだ理解が追いついていない部分を学習していきたいと思います。
 
 
初めてJSみた時はこんなの読めないと思っていましたが
今は少し見慣れてパーツごとに見れるようになったのが嬉しいです。
 
 
 
 
最後まで読んでくださってありがとうございました!
ではまた〜

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

JavaScriptのライブラリJQueryでイベント発火・Ajax(非同期通信を実装する場合)

前提

  • 非同期通信
  • Ruby.Rails
  • 送信フォームが送信(sendボタン押すイベント発火)されたらカラーのパネルが追加させる実装を行うことを例にする。
  • <例>発火すると右上に選択した色が非同期通信で表示される。

スクリーンショット 2020-10-16 15.09.31.png

 

イベントが発火した際にあることが実行されるようにする

①何をきっかけに(=イベントは何?)
②イベントきっかけにどんなとこを実行するか

この2つを考えながらコードを考える。

「今回は送信ボタンを押したら(イベント)カラーパネルが追加されることが実行される」

①送信ボタンを押すということは「フォームが送信された時」だと考える。
②イベントをきっかけにカラーパネルが表示されるにはいくつかの工程が必要だと考える。
 →Ajaxを使用(データ関連の引き渡し)
 →HTMLで変化後の見た目(イベント発火をきっかけに起こる一部見た目の変化)

①何をきっかけに(イベント発火は何?)

きっかけはフォームの送信

「フォームのボタンを押した時」というのを記述。

###.js(JavaScriptファイル)
$(function(){
  $(*****).on(*****, function(){

  })
})

フォームに設定したのクラス名を $( )に入れて、
「.on」で押すという意味を加える。
「on( , 」のon( の後には何を押すのかをいれる。
今回は'submit'ボタンを入れた。

<記述例>
$(function(){
  $('.js-form').on('submit', function(){

  })
})

また、console.logを用いてイベント発火しているか確認もしてみてください。
空いている行に記述して送信ボタンを押すことで確認できます。
<例>console.log("テスト")
などカッコに入れてみてください。
スクリーンショット 2020-10-16 16.15.58.png
できていない時は検証のコンソールでエラーが出るはずです。

  

次に、デフォルト設定の方のフォーム送信を停止

今のままだとデフォルトの設定として、
フォーム送信と共に画面が今まで通り(非同期通信ではなく)画面遷移(画面移動)してしまう。
通常設定は阻止する必要がある。
非同期通信を行うために、preventDefault()を使用する。

###.js(JavaScriptファイル)
  $(*****).on(*****, function(e){
    e.preventDefault()

  })
})

この際も真ん中の空いている行にconsole.logを入れてエラーが出てないか確認してみてください。
 
 
 

②イベントきっかけにどんなとこを実行するか

  • Ajaxを使用(データ関連の引き渡し)
  • HTMLで変化後の見た目(イベント発火をきっかけに起こる一部見た目の変化)

Ajaxを使用(データ関連の引き渡し)

この後必要になる基本のコード
先ほどのコードに 「$.ajax({」から追加しています。

javascripts/###.js
$(function(){
  $(*****).on(*****, function(e){
    e.preventDefault()
    // ここから下追加記述
    $.ajax({
      url: 取得したリクエストURL,  //同期通信でいう『パス』
      type: 'POST',  //同期通信でいう『HTTPメソッド』
      data: 取得したFormData,  
      dataType: 'json',
      processData: false,
      contentType: false
    })
  })
})

↑この記述を行っても遷移先のviewファイル(〇〇.json.jbuilder)を作成していないとエラーが出ます。
 

ここからは送信フィームをイベントとした例を元にみていきます。

<例>
$(function() {
  $('.js-form').on('submit', function(e) {
    e.preventDefault();
    // ここから下追加記述
    let formData = new FormData(this);
    let url = $(this).attr('action');
    $.ajax({
      url: url,
      type: "POST",
      data: formData,
      dataType: 'json',
      processData: false,
      contentType: false
    })
  });
});

 

「フォームに入力された値を受け取れるようにする記述をする」
FormData

フォームのデータの送信に使用。
new FormData(フォーム要素)とすることでFormDataを作成。
今回の場合オブジェクトの引数はthis。
イベントで設定したfunction内でthisを利用した場合は、
イベントが発生したノード要素を指す。
今回の場合は、js-formというクラスがついたフォームの情報を取得している。
IDなどでも取得できる。

<例>のFormDataについて
   let formData = new FormData(this);

 

attrメソッド

引数に指定した属性の値を取得することができる。

<例>のattrメソッドとurlについて
let url = $(this).attr('action');

例では引数に'action'を指定しているので(ここではthis)from要素のaction属性の値が取得できる。
スクリーンショット 2020-10-16 19.16.40.png

「/songs/3/songcolors」このパスがactionから取れてurlに入れられてる。
そのurlがAjaxのurlに関わってくるのだと思います。
  
 
 

「$.ajax」の部分に非同期通信に必要なオプションを設定
<例>$.ajaxからの記述
    $.ajax({
      url: url,
      type: "POST",
      data: formData,
      dataType: 'json',
      processData: false,
      contentType: false
    })
オプション 内容
type HTTP通信の種類を記述する。通信方法は、GETとPOSTの2種類。
url リクエストを送信する先のURLを記述する。遷移先、パス
data サーバに送信する値を記述する。今回はデータを格納したものが入る。
dataType サーバから返されるデータの型を指定する。
processData デフォルトではtrue。dataに指定したオブジェクトをクエリ文字列(例: msg.txt?b1=%E3%81%8B&b2=%E3%81%8D )に変換する役割。
contentType サーバにデータのファイル形式を伝えるヘッダ。FormDataをつかってフォームの情報を取得した時には必ずfalseにする。さらに詳しくはこちら

  
 
 

 

HTMLで変化後の見た目(イベント発火をきっかけに起こる一部見た目の変化)

非同期通信の結果(ブラウザの見た目としての変化)として返ってくるデータは、done(function(data) { 処理 })の関数の引数で受け取る。
doneメソッドを使う。

また、doneメソッドで受け取った引数( )を元に「function buildHTML〜」の後からHTMLを組み立てる。

javascripts/###.js
$(function(){
  //ここから下5行追記
  function buildHTML(***jsファイル名***){
    let html = `<*******>
                </*******>`//`から`の間にHTMLが入る。
    return html;
  }
  $(*****).on(*****, function(e){
    e.preventDefault()
    let formData = new FormData(this); //フォームからデータをとってくる場合この一文を必要とする。
    let url = $(this).attr('action'); //フォームのアクションに指定されたものが必要になる場合この一文が必要。
    $.ajax({
      url: 取得したリクエストURL,  //同期通信でいう『パス』
      type: 'POST',  //同期通信でいう『HTTPメソッド』
      data: 取得したFormData,  
      dataType: 'json',
      processData: false,
      contentType: false
    })
   //ここから以下追記
    .done(function(data){
      let html = buildHTML(data);
      $('.***ボタンのクラス***').prop('disabled', false) //一度押すと押せなくなる送信ボタンを連続で押せるようにしている
      $('***元のHTMLに追加したい場所を指定***').prepend(html);//.prepend指定した要素の最初に、引数で指定した内容を追加
    })
  })
})
doneメソッド

.when( ) は先に実行したい処理。
.done( ) は後で実行したい処理。
のように処理をいつしたいか設定できます。
 

$('.ボタンのクラス').prop('disabled', false)

disabled属性をfalseにする記述でsubmitボタンが押せないのをfalseで解除する。
 

function buildHTMLL( ){let html = `<****></****>return html;}

doneメソッドで受け取った引数( )を元にHTMLを組み立てる。
HTMLの組み立てはつど全く違っているのでここに記述しておりませんが自分のコードを例に置いておいきます。

<例>HTMLの箇所をピックアップしたもの
  function buildHTML(songcolor){
    let html =
      `<li class="color-box" style="background-color:${songcolor.color}"></li>`
    return html;
  };

検証ツールで追加したいHTMLを見てみるととてもわかりやすいのと、
データベースの情報を表示する際は${}を使用すること、
ここに持ってくる情報は対応するviweに作った.json.jbuilderに設定したことを思い出すとわかりやすいかも。

 

prependメソッド

元のHTMLのどの部分に追加するのかクラスなどを指定して決める。
指定した要素(クラスなど)の最初に足すことができる。
そのほかにも最後に足したりするメソッドなども存在する。
 

 

 

このように様々なメソッドを使用することで、
テキストボックス内をイベント後に空にしたり設定することができる。

 
 
 
 
 

イベント発火により実行することが実装できたら…

その実行ができなかった場合を想定する

javascripts/###.js
$(function(){
  function buildHTML(******){
    let html = `<*******>
                </*******>`
    return html;
  }
  $(*****).on(*****, function(e){
    e.preventDefault()
    let formData = new FormData(this);
    let url = $(this).attr('action');
    $.ajax({
      url: 取得したリクエストURL,
      type: 'POST',
      data: FormData,  
      dataType: 'json',
      processData: false,
      contentType: false
    })
    .done(function(data){
      let html = buildHTML(data);
      $('.******').prop('disabled', false)
      $('******').prepend(html);
    })
   //ここから以下追記
    .fail(function(){
      alert('error');
   });
  })
})
failメソッド

サーバーエラーの場合にdoneではなくfailが呼び出される。
 

alertメソッド

アラートが呼び出される。('****')の中身の文字がアラートで表示される。
 
 
 
 
 
 
以上です!
これで非同期通信の作業は最後です。
ほかにも様々な設定ができるのでこればかりではないのですが、
一旦ここで終わります。
 
 
 
 

最後にひとこと

ここまでまとめてみて、
一つ一つの記述の意味がより理解できました。
ただ、実際に新たに自分のオリジナルのアプリを開発したからというのも合わさって
今回の理解につながったのだと思います。

新たな疑問点や課題

  • 非同期通信をする際の手順を自分で思い出しながら実装できるかの不安
  • doneメソッドの引数であるHTMLの組み立て
  • done後の様々な記述
  • Ajax後の設定が他で応用できるのか
  • 非同期通信以外にJavaScriptでできることがあるがどんな仕組みなのか    

理解が深まっていても実装で使用できるか
また、まだまだ理解が追いついていない部分を学習していきたいと思います。
 
 
初めてJSみた時はこんなの読めないと思っていましたが
今は少し見慣れてパーツごとに見れるようになったのが嬉しいです。
 
 
 
 
最後まで読んでくださってありがとうございました!
ではまた〜

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

Ruby on Rails で特定のViewにCSS を適用する

Ruby on Rails で作ったWebアプリケーションのあるページで、Tableタグで作った表中の文字が上揃えになっていました。
このままでは見た目が悪いので、上下中央揃えとなるよう、CSSを適用する方法を調べましたので自分用メモとして残します。

1.何を修正すれば良いのか?

/marketpurser/app/assets/stylesheets 内のファイルです。
デフォルトで存在するapplication.scss に追記すると、すべてのViewに適用されます。
また、Viewの名前に対応した.scssファイルに追記すると、特定のViewのみに適用されます。

2.どう記述すれば良いのか?

CSSと同じ文法で良いようです。
今回はtableクラスを持ったtableタグ内の、tdタグに適用したいので、以下のように記述しました。

/marketpurser/app/assets/stylesheetssample.scss
table.table td {
 vertical-align:middle;
}
sample.html.erb
<table class="table">
  <thead>
    <tr>
      <th>#</th>
      <th>Info</th>
    </tr>
   </thead>
   <tbody id="myTable">
    <tr>
      <td>1</td>
      <td>data1</td>
    </td>
   </tbody>
</table>

解決しました。
なお、単にブラウザを再読み込みするのではなく、もう一度修正したViewのページにアクセスしないとCSSが反映されませんでした。(初歩的なミス)

以上、個人的なメモでした。

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

certbot停止からの再インストール

はじめに

certbotが死にました。。
というよりかは本番環境で運用していたhttps通信の証明証がいきなり破棄されて、戻すのに大変だったので備忘録。

開発環境

ruby 2.5.7
Rails 5.2.3
AWS ec2
nginx
puma

手順

cd ~
rm -r -f certbot
git clone https://github.com/certbot/certbot.git
cd certbot/
chmod a+x certbot-auto
sudo ./certbot-auto --nginx --debug 
※あとはyesに答えるだけ

エラー集

エラー①

エラーコード

Traceback (most recent call last):
  File "<stdin>", line 27, in <module>
  File "<stdin>", line 19, in create_venv
  File "/usr/lib64/python2.7/subprocess.py", line 185, in check_call
    retcode = call(*popenargs, **kwargs)
  File "/usr/lib64/python2.7/subprocess.py", line 172, in call
    return Popen(*popenargs, **kwargs).wait()
  File "/usr/lib64/python2.7/subprocess.py", line 394, in __init__
    errread, errwrite)
  File "/usr/lib64/python2.7/subprocess.py", line 1047, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory

原因

  • pythonのバージョンの不一致

改善コード

alternatives --set python /usr/bin/python2.7

エラー②

エラーコード

pkg_resources.DistributionNotFound: The 'virtualenv==15.1.0' distribution was not found and is required by the application

原因

  • virtualenvのバージョンの不一致

改善コード

sudo pip uninstall virtualenv
pip install virtualenv==15.1.0

エラー③

エラーコード

pkg_resources.DistributionNotFound: The 'pip==9.0.3' distribution was not found and is required by the application

原因

  • pipのバージョンの不一致

改善コード

sudo easy_install pip == 9.0.3

参考サイト

https://yoshinorin.net/2018/09/10/letsencrypt-cannot-update/

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

"~"で任意の文字を囲む方法

【概要】

1.結論

2.どのようにコーディングするか

3.開発環境

1.結論

gets.chomp、lengthメソッドを使用する!!


2.どのようにコーディングするか

str = gets.chomp #---❶
str_length = str.length
puts('~' * (str_length + 2)) #---❷
puts('~'+str+'~') #---❸
puts('~' * (str_length + 2)) #---❷

このようにすると、下記のようになります。
スクリーンショット 2020-10-17 15.41.09.png

❶:.chompを入れないと下記のようになります。改行をして2行目の最後の"~"をくっつけています。
スクリーンショット 2020-10-17 15.42.50.png
❷:lengthメソッドで入力したの文字の長さに +2しています。+2する理由は左上の"~"と右上の"~"の角っこを加えています。
❸:入力した文字の両端に"~”を加えています。

3.開発環境

Mac catalina 10.15.4
Vscode
Ruby 2.6.5
Rails 6.0.3.3

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

【Ruby on Rails】gem kaminariとjscrollを使用した無限スクロール

開発環境

ruby 2.5.7
Rails 5.2.4.3
OS: macOS Catalina

流れ

1 gemの導入
2 jscrollの導入
3 コントローラーの編集
4 viewの編集
5 jsの編集
6 CSSの編集

gemの導入

Gemfile
gem 'jquery-rails'
gem 'kaminari'
ターミナル
$ bundle install
$ rails g kaminari:config
$ rails g kaminari:views default
app/assets/javascripts/application.js
//= require jquery ←追加
//= require jquery_ujs ←追加
//= require activestorage
//= require turbolinks
//= require_tree .

参考:kaminari
【Ruby on Rails】ページング機能導入

jscrollの導入

①または②で導入します。

https://github.com/pklauzinski/jscroll/tree/master
こちらのGitHubからzipファイルをダウンロード後、
dist内にあるjquery.jscroll.min.jsを
app/asset/javascripts配下に保存してください。

②head内に書く場合はこちらを使用してください。

<script src="https://cdnjs.cloudflare.com/ajax/libs/jscroll/2.4.1/jquery.jscroll.min.js"></script>

①または②を導入後下記のように記述。
※//= require jqueryの下に記述するようにしてください。

app/assets/javascripts/application.js
//= require jquery
//= require jquery_ujs
//= require jquery.jscroll.min.js ←追加
//= require activestorage
//= require turbolinks
//= require_tree .

コントローラーの編集

.page(params[:page]).per(20)を記述することにより、
20個の要素を表示します。

app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def index
    @posts = Post.page(params[:page]).per(20)
  end
end

viewの編集

div内のクラス名をjQueryで編集していきます。

app/viws/posts/index.html.erb
<div class="scroll-list jscroll">
  <% @posts.each do |post| %>
    <span><%= post.post_title %></span>
  <% end %>
  <%= paginate @posts %>
</div>

jsの編集

今回は画面下5%までスクロールした際に
新しくロードするようにします。
※クラス名は先程指定したものをお使いください。

app/assets/javascripts/application.js
$(window).on('scroll', function() {
  scrollHeight = $(document).height();
  scrollPosition = $(window).height() + $(window).scrollTop();
  if ( (scrollHeight - scrollPosition) / scrollHeight <= 0.05) {
    $('.jscroll').jscroll({
      contentSelector: '.scroll-list',
      nextSelector: 'span.next:last a'
    });
  }
});

CSSの編集

app/assets/stylesheets/application.scss
nav.pagination {
  display: none;
}
.scroll-list {
  padding: 0;
}

まとめ

無限スクロールはTwitterやインスタグラムでも採用されているため、
表示が多い場合は導入すべき機能になります。

またtwitterではQiitaにはアップしていない技術や考え方もアップしていますので、
よければフォローして頂けると嬉しいです。
詳しくはこちら https://twitter.com/japwork

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

ARC104のD Multiset MeanをScala、Java、C++、Ruby、Perl、Elixirで解く

AtCoder ARC104の4問目をScala、C++、Java、Ruby、Perl、Elixirで解きました。言語ごとの処理速度の比較ができました。

問題へのリンク

結果

言語 結果
Scala TLE
C++ AC 1830ms
Java AC 2995ms
JavaっぽいScala AC 2991ms
Ruby TLE
Perl TLE
Elixir TLE

競技プログラミングにおける言語の選択と処理速度の関係は以下のツイートに言及がありました。

https://twitter.com/chokudai/status/1171321024224186369

このツイートによると、C++、Javaは大丈夫だけど、他の言語は計算量がシビアな問題には厳しいようです。

競技中は解法を見つけ出すのに時間がかかり、わかったあとはScalaで書いたものの、バグ取りに手間取って、AC(正解)に至りませんでした。競技後も続けたものの、どうしても実行時間制限4秒のTLEを解消できませんでした。

あきらめて同じロジックをC++で書いたらあっさりACを取れました。

そこで、せっかくなのでいろんな言語で書いてみて、AC取れるかを比較した結果です。

Scalaは最初はTLEだったものの、JavaでAC取ったあとにJavaを翻訳したようなScalaを書いたらScalaでもACとれました。

この記事の残りは各言語のソースコードです。

Scala

Arrayを使うなど中途半端にJavaっぽいScalaコードですが、TLEを解消できずにあきらめたコードです。

object Main extends App {
  val sc = new java.util.Scanner(System.in);
  val n, k, m = sc.nextInt();

  val table = (0 until n).map(i => Array.fill(i * (i+1) * k / 2 + 2)(0));
  table(0)(0) = 1;
  (1 until n).foreach { i =>
    val j_max = i * (i+1) * k / 2;
    val t1 = table(i - 1);
    val t2 = table(i);
    (0 to j_max).foreach { j =>
      val a1 = (((j - (i - 1) * i * k / 2) + i - 1) / i) max 0;
      val a2 = (j / i) min k;
      val s = (a1 to a2).map { a =>
        t1(j - a * i).toLong;
      }.sum % m;
      t2(j) = s.toInt;
    }
  }

  val table2 = Array.fill(n+1)(0);
  (1 to n).foreach { x =>
    if (x <= (n + 1) / 2) {
      val (n1, n2) = (x - 1, n - x);
      val s = (0 to (n1 * (n1+1) * k / 2)).map { i =>
        table(n1)(i).toLong * table(n2)(i) % m;
      }.sum % m;
      val answer = ((m.toLong + s * (k+1) - 1) % m).toInt;
      table2(x) = answer;
      println("%d".format(answer));
    } else {
      val answer = table2(n + 1 - x);
      println("%d".format(answer));
    }
  }
}

後述のJavaでAC取れたあと、JavaをScalaに翻訳したようなコードを書いたところ、Javaとほぼ同じ2991msでした。Scalaでこういうコードを書くぐらいならJavaでいいわけで、Scalaは計算量が厳しい問題には向いていないという結論です。Scalaは私にとって書きやすいので今後も使い分ければよいです。

object Main extends App {
  val sc = new java.util.Scanner(System.in);
  val n, k, m = sc.nextInt();

  val table = new Array[Array[Int]](n);
  table(0) = new Array[Int](2);
  table(0)(0) = 1;
  var i: Int = 1;
  while (i < n) {
    val j_max = i * (i+1) * k / 2;
    val t1 = table(i - 1);
    val t2 = new Array[Int](i * (i+1) * k / 2 + 2);
    table(i) = t2;
    var j: Int = 0;
    while (j <= j_max) {
      val a1 = (((j - (i - 1) * i * k / 2) + i - 1) / i) max 0;
      val a2 = (j / i) min k;
      var s: Long = 0L;
      var a: Int = a1;
      while (a <= a2) {
        s += t1(j - a * i).toLong;
        a += 1;
      }
      t2(j) = (s % m).toInt;
      j += 1;
    }
    i += 1;
  }

  val table2 = new Array[Int](n+1);
  var x: Int = 1;
  while (x <= n) {
    if (x <= (n + 1) / 2) {
      val (n1, n2) = (x - 1, n - x);
      var s: Long = 0L;
      var i: Int = 0;
      var max = (n1 * (n1+1) * k / 2);
      while (i <= max) {
        s += table(n1)(i).toLong * table(n2)(i) % m;
        i += 1;
      }
      s = s % m;
      val answer = ((m.toLong + s * (k+1) - 1) % m).toInt;
      table2(x) = answer;
      println("%d".format(answer));
    } else {
      val answer = table2(n + 1 - x);
      println("%d".format(answer));
    }
    x += 1;
  }
}

C++

同じロジックをC++で書き直したところ、1830msでAC取れました。

#include <bits/stdc++.h>
using namespace std;

int main() {
  int n, k, m;
  cin >> n >> k >> m;

  vector<vector<int>> table(n);
  table[0] = vector<int>(2);
  table[0][0] = 1;
  for (int i = 1; i < n; i++) {
    auto t1 = table[i-1];
    auto t2 = vector<int>(i * (i+1) * k / 2 + 2);
    int j_max = i * (i+1) * k / 2;
    for (int j = 0; j <= j_max; j++) {
      int a1 = ((j - (i - 1) * i * k / 2) + i - 1) / i;
      if (a1 < 0) a1 = 0;
      int a2 = j / i;
      if (a2 > k) a2 = k;
      long s = 0;
      for (int a = a1; a <= a2; a++) {
        s += t1[j - a * i];
      }
      s = s % m;
      t2[j] = (int)s;
    }
    table[i] = t2;
  }

  auto table2 = vector<int>((n + 1) / 2 + 1);
  for (int x = 1; x <= (n + 1) / 2; x++) {
    int n1 = x - 1;
    int n2 = n - x;
    long s = 0;
    for (int i = 0; i <= n1 * (n1+1) * k / 2; i++) {
      s += (long)table[n1][i] * table[n2][i] % m;
    }
    int answer = (int)(((long)m + s * (k+1) - 1) % m);
    table2[x] = answer;
    printf("%d\n", answer);
  }
  for (int x = (n + 1) / 2 + 1; x <= n; x++) {
    printf("%d\n", table2[n + 1 - x]);
  }
}

Java

C++でACが取れ、解法が間違ってないことがわかりましたので、次はJavaで書きました。2995msでAC取れました。C++よりは遅いものの、同じJVMのScalaよりも高速です。JVMでできるということは、ScalaでもJavaっぽい書き方にすればできるはずと考えたところ、ScalaでもACが取れたのは先述のとおりです。

import java.util.Scanner;

class Main {
  public static void main(String[] args) {
    var sc = new Scanner(System.in);
    var n = sc.nextInt();
    var k = sc.nextInt();
    var m = sc.nextInt();

    var table = new int[n][];
    table[0] = new int[2];
    table[0][0] = 1;
    for (int i = 1; i < n; i++) {
      var t1 = table[i-1];
      var t2 = new int[i * (i+1) * k / 2 + 2];
      int j_max = i * (i+1) * k / 2;
      for (int j = 0; j <= j_max; j++) {
        int a1 = ((j - (i - 1) * i * k / 2) + i - 1) / i;
        if (a1 < 0) a1 = 0;
        int a2 = j / i;
        if (a2 > k) a2 = k;
        long s = 0;
        for (int a = a1; a <= a2; a++) {
          s += t1[j - a * i];
        }
        s = s % m;
        t2[j] = (int)s;
      }
      table[i] = t2;
    }

    var table2 = new int[(n + 1) / 2 + 1];
    for (int x = 1; x <= (n + 1) / 2; x++) {
      int n1 = x - 1;
      int n2 = n - x;
      long s = 0;
      for (int i = 0; i <= n1 * (n1+1) * k / 2; i++) {
        s += (long)table[n1][i] * table[n2][i] % m;
      }
      int answer = (int)(((long)m + s * (k+1) - 1) % m);
      table2[x] = answer;
      System.out.printf("%d\n", answer);
    }
    for (int x = (n + 1) / 2 + 1; x <= n; x++) {
      System.out.printf("%d\n", table2[n + 1 - x]);
    }
  }
}

Ruby

TLEでした。

n, k, m = gets.strip.split(" ").map(&:to_i)

table = [[1]]
for i in 1..n-1
  t1 = table[i-1]
  t2 = []
  for j in 0 .. i * (i+1) * k / 2
    a1 = ((j - (i - 1) * i * k / 2) + i - 1) / i;
    a1 = 0 if a1 < 0
    a2 = j / i;
    a2 = k if a2 > k
    s = 0;
    for a in a1 .. a2
      s += t1[j - a * i]
    end
    s = s % m
    t2.push(s)
  end
  table.push(t2)
end

table2 = [0]
for x in 1 .. (n + 1) / 2
  n1 = x - 1
  n2 = n - x
  s = 0
  for i in 0 .. n1 * (n1+1) * k / 2
    s += table[n1][i] * table[n2][i] % m;
  end
  answer = (m + s * (k+1) - 1) % m
  table2.push(answer)
  p answer
end
for x in (n + 1) / 2 + 1 .. n
  p table2[n + 1 - x]
end

Perl

TLEでした。

use strict;
use warnings;
use integer;

my $nkm = <STDIN>;
$nkm =~ s/\n\z//;
my ($n, $k, $m) = split(/ /, $nkm);

my $table = [[1]];
for (my $i = 1; $i < $n; $i++) {
    my $t1 = $table->[$i - 1];
    my $t2 = [];
    my $j_max = $i * ($i + 1) * $k / 2;
    for (my $j = 0; $j <= $j_max; $j++) {
        my $a1 = (($j - ($i - 1) * $i * $k / 2) + $i - 1) / $i;
        $a1 = 0 if $a1 < 0;
        my $a2 = $j / $i;
        $a2 = $k if $a2 > $k;
        my $s = 0;
        for (my $aa = $a1; $aa <= $a2; $aa++) {
            $s += $t1->[$j - $aa * $i];
        }
        $s = $s % $m;
        push(@$t2, $s);
    }
    push(@$table, $t2);
}

my $table2 = [0];
for (my $x = 1; $x <= ($n + 1) / 2; $x++) {
    my $n1 = $x - 1;
    my $n2 = $n - $x;
    my $s = 0;
    for (my $i = 0; $i <= $n1 * ($n1+1) * $k / 2; $i++) {
        $s += $table->[$n1]->[$i] * $table->[$n2]->[$i] % $m;
    }
    my $answer = ($m + $s * ($k+1) - 1) % $m;
    push(@$table2, $answer);
    printf("%d\n", $answer);
}
for (my $x = ($n + 1) / 2 + 1; $x <= $n; $x++) {
    printf("%d\n", $table2->[$n + 1 - $x]);
}

Elixir

TLEでした。

defmodule Main do
  def main do
    [n, k, m] = IO.read(:line) |> String.trim() |> String.split(" ") |> Enum.map(&String.to_integer/1)
    table = Enum.reduce(1 .. n, [[1, 0]], fn i, acc ->
      [t1 | _] = acc
      j_max = div(i * (i+1) * k, 2);
      t2 = Enum.map(0 .. j_max, fn j ->
        a1 = max(div((j - div((i - 1) * i * k, 2)) + i - 1, i), 0)
        a2 = min(div(j, i), k)
        rem(Enum.reduce(a1 .. a2, 0, fn a, acc3 ->
          acc3 + Enum.at(t1, j - a * i)
        end), m)
      end)
      [Enum.reverse(t2) | acc]
    end) |> Enum.reverse

    table2 = (1 .. div(n + 1, 2)) |> Enum.map(fn x ->
      [n1, n2] = [x - 1, n - x]
      s = Enum.reduce(0 .. div(n1 * (n1 + 1) * k, 2), 0, fn i, acc ->
        rem((table |> Enum.at(n1) |> Enum.at(i)) * (table |> Enum.at(n2) |> Enum.at(i)) + acc, m)
      end)
      rem(m + s * (k+1) - 1, m)
    end)
    (1 .. n) |> Enum.each(fn x ->
      if x <= div(n + 1, 2) do
        IO.puts(Enum.at(table2, x - 1))
      else
        IO.puts(Enum.at(table2, n - x))
      end
    end)
  end
end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ゴリゴリの初心者がrails consoleを用いたデータベースの操作方法について纏めてみたンティウヌス

今回はrails consoleを用いてたデータベースの操作方法について簡単に纏めます。
※間違いへの指摘などありましたら、どしどしお寄せください!!

①テーブルにデータを追加する。

  $rails console
  ///以下、コマンドではPost.newでコンテンツカラムに"Hello World"を追加したことになります。
  post = Post.new(content:"Hello World")

②投稿を保存する。

  $rails console
  post = Post.new(content:"Hello World")
  ///以下、コマンドで投稿を保存する。
  post.save

③データを取得して、参照する。

  $rails console
  post = Post.new(content:"Hello World")
  post.save
  ///以下、データを取得する。
  post = Post.first
  ///取得したデータとデータベースに保存されているデータが一致することを目視で確認。
  post.content

シンプルすぎてわかりづらいですが、説明の精度は今後上げていくことにします。。笑

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

RailsにBootstrapを導入する方法

RubyにBootstrapを導入する方法

手順

  • Bootstrapのインストール
  • SCSSファイルの作成
  • JSファイルの修正
  • Rails(Puma)の再起動 ## Bootstrapをgemでインストール
Gemfile
gem 'bootstrap', '~> 4.3.1'
gem 'jquery-rails'
ターミナル
bundle install

SCSSファイルを作成

ターミナル
mv app/assets/stylesheets/application.css app/assets/stylesheets/application.scss
app/assets/stylesheets/application.scss
/*
 * This is a manifest file that'll be compiled into application.css, which will include all the files
 * listed below.
 *
 * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
 * vendor/assets/stylesheets directory can be referenced here using a relative path.
 *
 * You're free to add application-wide styles to this file and they'll appear at the bottom of the
 * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
 * files in this directory. Styles in this file should be added after the last require_* statement.
 * It is generally better to create a new file per style scope.
 *
 *= require_tree .    <(削除)
 *= require_self      <(削除)
 */
@import "bootstrap";  <(追加

JSファイルを修正

app/assets/javascripts/application.js
# 以下の3つを追記
//= require jquery3
//= require popper
//= require bootstrap

# 元々のコード
//= require rails-ujs
//= require activestorage
//= require turbolinks

Rails(Puma)を再起動

Dockerfile
# Railsに必要なパッケージをインストール
RUN apt-get update -qq && apt-get install -y nodejs
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - \
    && apt-get install -y nodejs

# 以下の公式サイトの記述ではnode.jsのバージョンが低くてbootstrapが使えない
# RUN apt-get update -qq && apt-get install -y nodejs

Bootstrapの使い方(テンプレート)

app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>App</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>
    <div class="d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom shadow-sm">
      <h5 class="my-0 mr-md-auto font-weight-normal">Company name</h5>
      <nav class="my-2 my-md-0 mr-md-3">
        <a class="p-2 text-dark" href="#">Features</a>
        <a class="p-2 text-dark" href="#">Enterprise</a>
        <a class="p-2 text-dark" href="#">Support</a>
        <a class="p-2 text-dark" href="#">Pricing</a>
      </nav>
      <a class="btn btn-outline-primary" href="#">Sign up</a>
    </div>
    <p class="notice"><%= notice %></p>
    <p class="alert"><%= alert %></p>
    <%= yield %>
  </body>
</html>

こうなる!

e8cf55d4ebff169216236d8d3dfac518.png

現場からは以上です!

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