【Illustrator】写真をフェードアウトする方法

本日は写真をフェードアウトする方法についての記事です。
こちらも何かと使う場面がある技法だと思うので書き留め。


操作手順

①画像を用意
f:id:programmingnuoh:20210330195542p:plain ②画像と同寸の図形を用意
f:id:programmingnuoh:20210330195628p:plain 今回はわかりやすいようにピンクの長方形を用意しています。
③長方形オブジェクトにグラデーションを適用
f:id:programmingnuoh:20210330195741p:plain 白黒のグラデーションをかけましょう。
④ウィンドウ>透明を選択
f:id:programmingnuoh:20210330195944p:plain ⑤2つのオブジェクトを選択、[透明から不透明マスクを作成]を選択
f:id:programmingnuoh:20210330200124p:plain 黒い部分が透明に,白い部分が元の写真をそのまま表示しています。
f:id:programmingnuoh:20210330200357p:plain


今回は写真をグラデーションする方法を学んでいきました!
イラレには他にも通常のグラデーションをする方法や文字に反映させる方法などもあるので、そのあたりも今後学んでいきたいですね。


今回はこちらを参考にさせていただきました。ありがとうございました。
イラレ グラデーションの基礎+絶対知りたい8つの知識…|Udemy メディア

自分に置き換えて [20210329☀️]

2021/03/29 本日のアウトプット。

・今日の積み上げ・

  • Rubyドリル
  • 最終課題/Basic認証機能 2:24
  • 英語学習 00:51
    • mikan 900 
    • Polyglots 1本
    • ディクトレ 5本
  • ライフコーチとの面談

本日の勉強時間 03:15

最終課題、ついにすべての機能にLGTMをいただきました〜!!
なんだかんだで3月以内に終わらせる、という目標をクリアできました。
明日からは追加機能でやっておいた方がいいよ、と言われたAWSの学習と、オリジナルアプリの本格的な構想に移ります。
それと自主学習で学びたいことがたくさんあるので、それもリストアップして順々に学習していきたいと思います。

・雑記・
今日はライフコーチとの面談がありました!
前回のときにオリアプについて先輩方の制作物を参考にしたいとお願いしたので、今日は発表時のパワポを見せていただきました。
みなさん、ご自身のご経験だったりご趣味だったりに関係した課題解決をされており、非常に参考になりました。
私も作りたいな〜と考えているのがいくつかほわっとしたのが頭の中にあるので、深掘りして自分の今の実力で作れるか、何を学習すればさらに機能を付随できるかなど考えていきたいと思います。

【Rails】アソシエーションでつながった他のテーブルの情報を表示する

実は初めましての機能。
今回制作している最終課題のフリマアプリは、ユーザー情報以外に商品に関して説明や値段を登録する商品情報と、購入した際に送り先の住所等を登録する購入情報のテーブル、それら二つを紐づけるテーブルにそれぞれ分かれています。
今回は、ビューファイルでの情報の表示について、2点記録します。


商品登録のテーブルにある情報を別の所で表示させたい

f:id:programmingnuoh:20210329220049p:plain
商品名や値段が載っています

ビューファイル(購入情報)の記述は以下の通り。

    <div class='buy-item-info'>
      <%= image_tag @item.image, class: 'buy-item-img' %>
      <div class='buy-item-right-content'>
        <h2 class='buy-item-text'>
          <%= @item.name %>
        </h2>
        <div class='buy-item-price'>
          <p class='item-price-text'>¥<%= @item.price %></p>
          <p class='item-price-sub-text'><%= @item.shipping_fee_status.name %></p>
        </div>
      </div>
    </div>

@itemに商品情報が入っています。
その商品情報を指定するコントローラー(購入情報)は以下の通り。

  @item = Item.find(params[:item_id])

今回の肝だな〜と感じるのはparamsのIDの指定。いつも使っていたparams[:id]を指定してしまうと、記述している場所(今回なら購入情報)のIDを取得してしまいます。
アソシエーションで繋がっていれば、上記のようなIDの指定の仕方が可能です。


紐付きの有無で表示を変える

f:id:programmingnuoh:20210329221537p:plain
購入した商品にはSOLDOUTの表示がされる
ビューファイル(商品情報)の記述は以下の通り。

<% if @item.order_item.present? %> 
  <div class='sold-out'>
    <span>Sold Out!!</span>
  </div>
<% end %>

アソシエーションで繋がっていれば、変数の後にモデルの指定をすることで繋がりの有無が確認できます。
あとは空か否かを判断するメソッドで確認。
関係するメソッドはコチラを参考にさせていただきました。
今回は、紐づきがtrueのときにSOLDOUTが表示されるようpresent?メソッドを使用しました。


まとめ

今回はかなり自分本位のまとめになりました…。
完全に自分しかわかりませんね。
見てしまった方にはごめんなさい。
各モデルのアソシエーションがわからなくなってしまったとき等、実装がわからなくなったときにここの記事に戻ろうと思います。


今回、以下の記事を参考にいたしました。ありがとうございました。 ActiveRecord::RecordNotFound in 小説サイトを参考に真似をし練習中に起きたエラーです。
rubyの真偽判定メソッド(nil?/empty?/blank?/present?)を検証してみた結果、興味深いことがわかった

立ち止まり、でも停滞はしない [20210327☀️]

2021/03/26 本日のアウトプット。


・今日の積み上げ・


Rubyドリル

記事作成 2本 05:37

英語学習 00:41
mikan 900 

Polyglots 1本

ディクトレ 5本

 


本日の勉強時間 06:18

 

今日は購入機能で新しく学んだ機能や、遭遇したエラーの整理とアウトプットをしました。

改めて紙に書き出したりすると理解度が深まる気がします。

その代わりかなり時間がかかってしまいました。

理解度を深めると言う意味では時間をかけてもいいのかもしれませんが、やはりどんどん進めて新しいインプットもしたいのでメリハリをつけて勉強していきたいと思います。


・雑記・

明日はお勉強はいったんお休みです。(単語とかはやりますが)

前々から予約していたビュッフェに行くので楽しみです!

休息をしっかり取って、来週以降頑張れるようにパワーためていきます💥

ちなみにですが…今日食べた汁なし担々麺も美味しかったのでこちらにもあげちゃいます。Twitterには先に載せちゃいましたが。


f:id:programmingnuoh:20210327185902j:image

へへ。

 

【Rails】Formオブジェクトパターンでの実装

複数のモデルのデータ定義の生成・更新で用いるFormオブジェクトパターン。
デザインパターン(実現したいゴールに対して最適な方法や手順をまとめたもの)の一つです。
アプリの商品購入機能において、こちらのパターンを使用して実装を行ったので、ここに備忘録を残しておきます。
ここの箇所、エラーがたくさん出て試行錯誤を繰り返した内容でもあります。
実装手順とともに、遭遇したエラーも記載して、内容の理解をさらに深めようと思います。


なぜFormオブジェクトパターンを使うのか?

今まで通り、一つのコントローラーの中にそれぞれのモデルに対してparamsを定義し、それをcreateしていけばいいのではないか。
そうすると、もし入力を間違った場合(バリデーションに引っかかった場合)に保存ができません。

f:id:programmingnuoh:20210327165829j:plain
Formオブジェクトパターンを用いた時の情報の流れ


実装の手順

①modelsディレクトリ直下にFormオブジェクト用のファイルを生成する

②生成したファイル内に、以下の記述を行う

class Order
  include ActiveModel::Model //①~
  attr_accessor :post_code, :prefecture_id, :city, :address, :building, :phone_number, :user_id, :item_id,:token  //~①
 
  with_options presence: true do //②~
    validates :post_code, format: {with: /\A[0-9]{3}-[0-9]{4}\z/, message: "例)123-4567"}
    validates :prefecture_id, numericality: {other_than: 0, message: "can't be blank"}
    validates :city
    validates :address
    validates :phone_number, format: {with: /\d{10,11}/}, length: {maximum: 11}
    validates :token
    validates :user_id
    validates :item_id
  end       //~②

  def save //③~
    order_item = OrderItem.create(user_id:user_id, item_id:item_id)
    Deliver.create(post_code:post_code, prefecture_id:prefecture_id, city:city, address:address,building:building,phone_number:phone_number, order_item_id:order_item.id)
  end  //~③

end

  • ①form_withメソッドに対応する機能とバリデーションを行う機能を持たせる記述を行う
    include ActiveModel::Modelを用いると、form_withやrenderを使えるようになったり、バリデーションの設定ができるようになります。
    attr_accessorメソッドでゲッターとセッターを定義することで、インスタンスを生成した際にform_withの引数として利用することができる。

  • ②バリデーションの記述
  • ③saveメソッドの定義
    ActiveRecordを継承していないため、saveメソッドを手入力で記述。
    そうすることで、テーブルへのデータ保存が可能になります。

    ③コントローラーにFormオブジェクトのインスタンスを生成する記述を行う

      def index
        @order = Order.new
      end
    
      def create
        @order = Order.new(order_params)
        if @order.valid?
          pay_item
          @order.save
          return redirect_to root_path
        else
          render 'index'
        end  
      end
    
    ~~省略~~
    
      def order_params
        params.require(:order).permit(:post_code, :prefecture_id, :city, :address, :building, :phone_number).merge(user_id: current_user.id, item_id: params[:item_id], token:params[:token])
      end
    

    current_userメソッドはコントローラー内に記述すること。(理由は後述)

    ④form_withメソッドを用いてインスタンスを渡せるような記述を行う

        <%= form_with model: @order, url: item_delivers_path,id: 'charge-form', class: 'transaction-form-wrap',local: true do |f| %>
    
        <%= render 'shared/error_messages', model: f.object %>
        
    ~~後略~~
    

    以下、ビューファイル記述の際の注意点です。

  • モデルはFormオブジェクトのモデルを設定。
  • エラーメッセージの表示のモデルもFormオブジェクトのモデルを設定。(今回はブロック変数が定義されているためそれを使用)
  • urlは必ず記述。(手入力で生成したファイルのため、直接該当するURLがないから。)

    実装中に遭遇したエラーを紐解く

    今回は、住所やクレジットカード情報を保存するdeliverモデルと、商品情報とdeliver情報を紐づけるorder_itemモデルのふたつをFormオブジェクトを用いて保存していきました。

    ①paramsについて、MissingParamsやNoMethodErrorになる


    f:id:programmingnuoh:20210327172944p:plain order_itemのparamsがないと怒られたり、アソシエーションが定義されていないと怒られました。

    ・原因・
    本来、紐付け用に生成したorder_itemモデルをFormオブジェクトとして使用し、そのなかにバリデーションとアソシエーションを定義していました。

    class Order
      include ActiveModel::Model
      attr_accessor :post_code, :prefecture_id, :city, :address, :building, :phone_number, :user_id, :item_id,:token
     
      with_options presence: true do
        validates :post_code, format: {with: /\A[0-9]{3}-[0-9]{4}\z/, message: "例)123-4567"}
        validates :prefecture_id, numericality: {other_than: 0, message: "can't be blank"}
        validates :city
        validates :address
        validates :phone_number, format: {with: /\d{10,11}/}, length: {maximum: 11}
        validates :token
        validates :user_id
        validates :item_id
      end
    
      def save
        order_item = OrderItem.create(user_id:user_id, item_id:item_id)
        Deliver.create(post_code:post_code, prefecture_id:prefecture_id, city:city, address:address,building:building,phone_number:phone_number, order_item_id:order_item.id)
      end
    
    
      belongs_to :user
      belongs_to :item
      has_one :deliver
      extend ActiveHash::Associations::ActiveRecordExtensions
      belongs_to :prefecture
    end
    

    今まで定義していたモデルは、すべてApplicationRecordが定義されていたため、バリデーションやアソシエーションが組めていました。
    Formオブジェクトは手入力で生成するので、アソシエーションやsaveメソッド、current_userメソッドは使えません。
    (バリデーションは、include ActiveModel::Modelを定義しているので使用可能。)

    ・解決策・
    Formオブジェクト内にはバリデーションのみ記述すること。

    ②値の取得・保存に関するエラー


    購入するitemのデータを取得したいのですが、findメソッドを使っても見つけることができません。
    f:id:programmingnuoh:20210327174239p:plain

    f:id:programmingnuoh:20210327174317p:plain
    試行錯誤の嵐
    ・原因・
  • paramsでの値の取得の仕方

      def item_find
        @item = Item.find(params[:id])
      end
    

    このままでは、orderモデルのparamsのIDを取得してしまいます。
    欲しいのはitemのID。

  • createするときの()内の記述

      def save
        order_item = OrderItem.create(user_id:user.id, item_id:item.id)
        Deliver.create(post_code:post_code, prefecture_id:prefecture_id, city:city, address:address,building:building,phone_number:phone_number, order_item_id:order_item.id)
      end
    

    ここの部分、ちゃんと理解していなかったのでなんとなくで書いていました。反省。

    ・解決策・

  • paramsの記述を以下に変更。

      def item_find
        @item = Item.find(params[:item_id])
      end
    

    params内の[]内は、paramsのどこの値を取得するかです。
    今回は、紐づいているitemのIDを取得したかったため、paramsmerge部分に記述されているカラム名を選択しています。

  • ②OrderItemのcreate()内を以下のように変更。

      def save
        order_item = OrderItem.create(user_id:user_id, item_id:item_id)
        Deliver.create(post_code:post_code, prefecture_id:prefecture_id, city:city, address:address,building:building,phone_number:phone_number, order_item_id:order_item.id)
      end
    

    そもそもの話ですが…

    Xxx.create(name: name,..........,user_id:user_id)
    

    このような記述があった場合、:の左側はテーブルのカラム名、右側はストロングパラメーターやattr_accecorメソッド、ビューなどに入力された値をそれぞれ指します。
    ここはなんとなくの私の認識なので間違っていたら訂正をお願いしたいのですが、
    user_id→カラム名とかform_with内とかで使用する名前で、値を入れる箱
    user.id→値そのもの。これをカラムとかの箱に入れる。
    このように認識しています。
    今回は、ビューファイル内等すべてuser_idで記述していたので、create()内の記述もこれに統一しました。


    まとめ

    Formオブジェクトを作成していく上では、モデル同士やモデルとコントローラー、ビューなどそれぞれの関係性をきちんと理解していないと記述できないな、と感じました。(だからエラー沼に落ちた…)
    流れの把握もそうなのですが、それぞれが値なのか、カラム名なのかという細かいところまで確認しながら実装していかないといけませんね。
    最初は時間がかかるかもしれませんが、徐々に慣れていきたいと思います。


  • 【Rails】PAY.JPを用いた購入機能の実装について

    購入機能の実装が一段落したので関連する機能およびエラーについてアウトプットしていきたいと思います。
    今回はPAY.JPを用いた購入機能の実装について。
    ネットでもリアルでもクレジットカードが使えない場面というのは今やほとんどないですよね。(ラーメン屋さんとかは券売機使ってるから現金のみのところも多い気がしますが)
    スタンダードな決済機能、しっかりと実装していきましょう!


    なぜオープンAPIを使うのか?

    そもそもの前提の話をまず記録しておきます。
    簡単な話、カード会社と直接連携しようとすると発生する以下2点の問題が解決できるからオープンAPIを使用します。

    • 会社ごとに事務的手続きをして連携しなければならない
    • 金銭の授受に関わるため、一定のセキュリティー基準をクリアしないといけない

    尚、カード情報を直接アプリケーションに送ってサーバーにデータを保存・処理を行うことが2018年6月以降、改正割賦販売法によって禁じられています。
    したがって、トークン(セキュリティを担保するために用いられる、一回のみ使用可能なパスワード)を使用して処理することで決済をおこないます。

    f:id:programmingnuoh:20210327122140j:plain
    PAY.JPを用いた決済機能の流れ


    実装の手順

    実装の流れとしては、クライアントサイド→クライアントサイド(トークン送付)→サーバーサイド(決済機能)です。

    ・クライアントサイド実装・
    ①turbolinksの確認
    今回は手作業でJavaScriptを記述してフォーム送信処理等を実装していくので、turbolinksは使用しません。
    そのため、以下2ファイルの記述を確認していきます。

  • app/views/layouts/application.html.erb

    <%# 省略 %>
        <%= stylesheet_link_tag 'application', media: 'all'  %>
        <%= javascript_pack_tag 'application' %>
    <%# 省略 %>
    

  • app/javascript/packs/application.js

    require("@rails/ujs").start()
    require("turbolinks").start()  →コメントアウトする
    require("@rails/activestorage").start()
    require("channels")
    

    turbolinksのチートシートコチラ

    ②クライアントサイドでPAY.JPのAPIを使用するために必要なJavaScriptを読み込む
    ビューファイルに以下の一文を記述し、JavaScriptを読み込ませます。

    <head>
      <title>Furima</title>
      <%= csrf_meta_tags %>
      <%= csp_meta_tag %>
      <script type="text/javascript" src="https://js.pay.jp/v1/"></script> //追記
      <%= stylesheet_link_tag 'application', media: 'all' %>
      <%= javascript_pack_tag 'application' %>
    </head>
    

    トークン化を行うJavaScriptファイルを作成
    app/javascriptディレクトリに直接JavaScriptファイルを生成。
    また、application.jsにrequire("xxx")を記述し、JSファイルが読み込まれるようにします(xxxがファイル名、階層があるときはそれも記述しよう)。
    手作業で生成したファイルに、以下を記述。

    const pay = () => {
      Payjp.setPublicKey(process.env.PAYJP_PUBLIC_KEY); //②
      const form = document.getElementById("charge-form"); //①~
      form.addEventListener("submit", (e) => {
        e.preventDefault();               //~①
    
        const formResult = document.getElementById("charge-form"); //③~
        const formData = new FormData(formResult);
    
        const card = {
          number: formData.get("order[number]"),
          cvc: formData.get("order[cvc]"),
          exp_month: formData.get("order[exp_month]"),
          exp_year: `20${formData.get("order[exp_year]")}`,
        };                                                //~③
    
         Payjp.createToken(card, (status, response) => { //④~
          if (status == 200) {
            const token = response.id; //~④
         }
        )};
      });
    };
    
    window.addEventListener("load", pay);
    

  • ①charge-formの部分は、フォーム全体を取得できるような記述をしています。
    また、この機能では送信時にイベント発火させたいため、"submit"を指定しています。
    各記述ごと(load時、submit時など)でconsole.logの記述をおこない、それぞれが正しく機能しているか確認しましょう。

  • ②PAY.JPのテスト公開鍵を取得、設定。
    PAY.JPの自身のアカウントページから公開鍵を確認します。
    ⚠︎自身の鍵情報は絶対に外に漏らさないように!GitHub上にもPushしないように注意⚠︎

    f:id:programmingnuoh:20210327125506p:plain
    アカウントページ、APIから確認。
    先の生成したJSファイル内に以下を追記し、公開鍵情報を読み込ませます。
    (すでに環境変数に定義しているため、環境変数が記述されています。)

  • トークン化の処理を行う
    FormDataとは、フォームに記載された値を取得できるオブジェクト。
    今回はcharge-formでフォーム全体を指定し、そこで入力された値をformDataとして生成します。
    また、cardで各フォームの情報を取得します。
    get以降の()内は各フォームのname属性を指定するのですが、必ず検証ツールから取得しましょう。
    exp_year(有効期限の年の部分)は20xx年になるように記述することも忘れずに!

  • ④カードの情報をトークン化する
    createTokenの第1引数にcard(取得したカード情報)、第2引数にstatus,responseをアロー関数(functionの代わりに() =>を用いて関数を定義)を用いて定義しています。
    statusにはHTTPのステータスコードresponseにはそのレスポンスの内容が入ります。
    変数tokenresponse.idを入れることで、トークンの値を取得できます。


    トークン送付に関するクライアントサイドの実装・
    トークン情報をフォームに追加・送信

    const pay = () => {
      Payjp.setPublicKey(process.env.PAYJP_PUBLIC_KEY);
      const form = document.getElementById("charge-form");
      form.addEventListener("submit", (e) => {
        e.preventDefault();
    
        const formResult = document.getElementById("charge-form");
        const formData = new FormData(formResult);
    
        const card = {
          number: formData.get("order[number]"),
          cvc: formData.get("order[cvc]"),
          exp_month: formData.get("order[exp_month]"),
          exp_year: `20${formData.get("order[exp_year]")}`,
        };
    
        Payjp.createToken(card, (status, response) => {
          if (status == 200) {
            const token = response.id;
            const renderDom = document.getElementById("charge-form"); //①~
            const tokenObj = `<input value=${token} name='token' type="hidden">`;
            renderDom.insertAdjacentHTML("beforeend", tokenObj);
          }                                                    //~①
    
          document.getElementById("card-number").removeAttribute("name"); //②~
          document.getElementById("card-exp-month").removeAttribute("name");
          document.getElementById("card-exp-year").removeAttribute("name");
          document.getElementById("card-cvc").removeAttribute("name"); //~②
    
          document.getElementById("charge-form").submit(); //③
        });
      });
    };
    window.addEventListener("load", pay);
    

  • トークンの情報をフォームに追加する
    トークン情報を送信できるフォームをinput要素で追加していきます。
    ここでのname属性はparamsで取得できるように設定しましょう。
    一度debugger;で処理を確かめてから、input要素をtype="hidden"で隠します。

  • ②クレジットカードの情報を削除
  • ③フォームの情報をサーバーサイドへ送る
    e.preventDefault();Railsの送信処理をキャンセルしているため、JavaScriptから送信するような記述を行います。


    ・サーバーサイドにおける実装・
    ①ストロングパラメーターにトークンの情報を追加

    def order_params
        params.require(:order).permit(:post_code, :prefecture_id, :city, :address, :building, :phone_number).merge(user_id: current_user.id, item_id: params[:item_id], token:params[:token])
    end
    

    ②モデルにトークンの情報を追加

    class Order < ApplicationRecord
      attr_accessor :token
     
    ~~省略~~
    

    attr_accessorメソッドとは、記述したクラスにゲッターとセッターを定義してくれるもの。
    モデルに対応するテーブルのカラム名以外を扱いたい時に使用する。
    ③PAY.JPによる決済処理

  • GEM 'payjp'を導入する
  • コントローラーに決済処理を記述

    def pay_item
        Payjp.api_key = ENV["PAYJP_SECRET_KEY"] //①
        Payjp::Charge.create( 
          amount: @item.price,
          card: order_params[:token],
          currency: 'jpy'
        )                     //②
    end
    

  • 秘密鍵の情報をインスタンスに代入
  • ②決済処理の記述
    Gemが提供しているPayjp::Charge.createというクラス及びクラスメソッドを使用して値段、カード情報、通貨単位の情報を保存する。

    ④バリデーションの設定
    空の情報は送信できないよう設定。

    validates :token, presence:true
    

    まとめ

    JavaScriptの記述にまだ慣れていないので、とっても難しく感じています
    どのname属性、IDなどの値を取得するのかなど、一つ一つの処理の意味を考えていけば自ずとわかるはず…
    なのでまずは流れを確認しながら、繰り返し復習していきたいと思います!


  • 一段落、でも止まらない [20210326☁️]

    2021/03/26 本日のアウトプット。

    ・今日の積み上げ・

    • Rubyドリル
    • 最終課題/購入機能実装 01:45
    • 英語学習 00:58
      • mikan 900 
      • Polyglots 1本
      • SANTA TOEIC 本日文

    本日の勉強時間 02:57

    購入機能の実装が終了しました〜〜!!!!!
    ここでの機能ははじめましての内容も、また頭に定着していない内容もてんこもりだった気がします。
    しっかり復習、まずは今までのエラー等のアウトプットをしていきます。
    記事に残していくことで自分の中の資料増やしていくぞ〜〜〜!!

    ・雑記・
    いよいよ最終課題も残るはベーシック認証と追加実装のAWS実装のみ。
    オリジナルアプリ制作、追加の自主学習、ポートフォリオサイトの制作とやることがたくさんです。
    でも今までより自由度が高いから楽しみです!
    自主学習はとにかく基礎固めとしてWebの基礎、LinuxJavaScriptをやっていきたいと思っています。詰め込みすぎなのかな?
    でもエンジニアとして働いていく上で、ちゃんと自分の中で基盤を構築していきたいと思っているのでしっかりやっていきたいと思います!