CarrierwaveでUUIDを使ったファイル名にする方法
UUIDとは
- Universally (普遍的に) Unique (一意な) IDentifier (識別子) の略
- 誰でも作れるが世界中で重複しないようになっているID
- RFC4122という共通の規格が決められている
UUIDの種類
- UUIDの作成方法には5種類存在する。
1: 時刻とMACアドレスを元にするバージョン 2: DCEセキュリティバージョン 3: バイト列を元にするバージョン。MD5ハッシュを利用 4: ランダム生成するバージョン 5: バイト列を元にするバージョン。SHA-1ハッシュを利用
- RubyのSecureRandom.uuidはバージョン4
- 16進数を32桁で乱数生成したもの
- 340澗(かん)通り。重複はしないと考えていい。
www.slideshare.net
なぜUUIDを使うのか?
- ファイル名にIDを使っている場合、推測ができてしまい他のユーザーが閲覧できてしまう
- IDからサービスのユーザー数がバレてしまう
上記のようなニーズからUUIDは使われる
UUIDにする方法
- xxx_uploader.rbのfilenameメソッドを上書きすればいい
def filename "#{SecureRandom.uuid}.#{file.extension}" if original_filename end
公式では以下のような書き方がサンプルにあるが、uuidだけでも十分だし読みやすいのでいいのではと思っている。
def filename "#{secure_token}.#{file.extension}" if original_filename.present? end protected def secure_token var = :"@#{mounted_as}_secure_token" model.instance_variable_get(var) or model.instance_variable_set(var, SecureRandom.uuid) end
Rails5でajaxを使っていいね機能を実装する
ルーティングを用意する
resources :diaries do resources :diary_comments, only: [:create] resources :diary_likes, only: [:create, :destroy] end
- diaryが重複するので後でスッキリさせる
モデルを用意する
class Diary < ApplicationRecord belongs_to :user has_many :diary_likes, dependent: :destroy # ユーザーのいいねを取得 def like(user_id) diary_likes.find_by(user_id: user_id) end end
部分テンプレートを用意する
<% if diary.like(user.id) %> <button class="btn btn-default btn-xs disabled" type="button"> <i class="fa fa-thumbs-o-up">いいね済み</i> </button> <% else %> <button class="btn btn-default btn-xs" type="button"> <i class="fa fa-thumbs-o-up">いいね</i> </button> <% end %> <% else %>
button_toに書き換える
<%= button_to diary_likes_path(diary), remote: true, class: "btn btn-default btn-xs" do %> <i class="fa fa-thumbs-o-up">いいね</i> <% end %>
- button_toは実際にはformとbuttonタグとして出力される。こんな感じ
<form class="button_to" method="post" action="/diaries/1/likes" data-remote="true" <button class="btn btn-default btn-xs" type="submit"> <i class="fa fa-thumbs-o-up">いいね</i> </button> <input type="hidden" name="authenticity_token" value="xx"> </form>
<% if diary.like(user_id) %> <%= button_to diary_diary_like_path(diary, diary.like(user_id)), remote: true, method: :delete, class: "btn btn-default btn-xs" do %> <i class="fa fa-thumbs-o-up">いいね済み</i> <% end %> <% else %> <%= button_to diary_diary_likes_path(diary), remote: true, class: "btn btn-default btn-xs" do %> <i class="fa fa-thumbs-o-up">いいね</i> <% end %> <% end %> <% else %>
いいねボタンを用意
.like-button{:class => "like-button-#{diary.id}"} = render "diary_likes/like", diary: diary, user_id: diary.user_id
- 日記ごとに部分テンプレート化したいいね!ボタンをrenderする
いいね機能を実装する
def create @like = DiaryLike.new(user_id: current_user.id, diary_id: params[:diary_id]) @like.save end def destroy @like = DiaryLike.find_by(user_id: current_user.id, diary_id: params[:diary_id]) @like.destroy end
- diary_idしか送られてこない & そのまま保存するわけでもないのでストロングパラメータは不要
- remote: trueで送っているので、xxx.js.erbが呼ばれる
create.js.erbを作成
$(".like-button-<%= @like.diary_id %>").html("<%= j(render partial: 'like', locals: { diary: @like.diary, user_id: @like.user_id }) %>")
destroy.js.erbを作成
$(".like-button-<%= @like.diary_id %>").html("<%= j(render partial: 'like', locals: { diary: @like.diary, user_id: @like.user_id }) %>")
laravelでURLパラメータを取得する
Route::get('user/{id}', 'UserController@show');
public function show(Request $request, $id) {
こんな感じで取得できる
react-nativeでbox-shadowをつける
IOSの場合
shadowColor: #ccc, shadowOffset: { width: 0, height: 2, }, shadowRadius: 0, shadowOpacity: 1,
- shadowOffset
- width: 横への影
- height: 縦の影
- shadowOpacity
- 影の透明度
- 0が透明、1は透明なし
これでこんな感じで下に影をつけられる
Androidの場合
shadowColor: #ccc, shadowOffset: { width: 0, height: 2, }, shadowRadius: 0, shadowOpacity: 1, elevation: 2
- Androidの場合はelevationをつける
yenta風の特定の位置までドラッグしたらフェードアウトする処理を実装する
$('.draggable').draggable({ drag: function() { var offset = $(this).offset(); var xPos = offset.left; var yPos = offset.top; if (xPos >= 210) { $('.xxx).addClass('fadeout-right').delay(700).fadeOut(1); } if (xPos <= -210) { $('.xxx).addClass('fadeout-left').delay(700).fadeOut(1); } if (yPos <= -250) { $('.xxx).addClass('fadeout-top').delay(700).fadeOut(1); } if (yPos >= 300) { $('.xxx).addClass('fadeout-bottom').delay(700).fadeOut(1); } } });
.fadeout-right { transform: rotate(30deg) scale(0.8); transition: 1s; opacity: 0; margin-left: 200px; } .fadeout-left { transform: rotate(-30deg) scale(0.8); transition: 1s; opacity: 0; margin-left: -200px; } .fadeout-top { transform: rotate(30deg) scale(0.8); transition: 1s; opacity: 0; margin-bottom: 200px; } .fadeout-bottom { transform: rotate(-30deg) scale(0.8); transition: 1s; opacity: 0; margin-bottom: -200px; }
ちなみにスマホだとブラウザのドラッグイベントが検知できないので、
jquery-ui-touch-pinch.js
のライブラリを使いました。
Railsでコメント機能を作る
ルーティングの追加
resources :diaries do resources :comments, only: [:create] end
コントローラー側
@diaryComment = DiaryComment.new(diary_comment_params) @diaryComment.user_id = User.first.id respond_to do |format| if @diaryComment.save format.html { redirect_to diaries_url, notice: 'Diary was successfully created.' } format.json { render :show, status: :created, location: @diaryComment } else format.html { redirect_to diaries_url } format.json { render json: @diaryComment.errors, status: :unprocessable_entity } end end def diary_comment_params # params.require(:diary).permit(:content) params.require(:diary_comment).permit(:content, :diary_id) end
フォームの追加
= form_for([diary, diary.diary_comments.build]) do |f| %img.img-responsive.img-circle.img-sm{:alt => "Alt Text", :src => "xxxx"}/ / .img-push is used to add margin to elements next to floating images .img-push = f.hidden_field :diary_id = f.text_field :content, class: "form-control input-sm", placeholder: "コメントを入力"
ポイント
- 1:多のform_forの指定
- ネストしたリソースのルーティング
今回はAjaxとしては実装しなかったのでまたそれは次回
Tinder風のUIをJavaScriptで実装する
https://codepen.io/developingidea/pen/meAIncodepen.io
こちらのコードを参考に学んでみた。
$(".buddy").on("swiperight",function(){ $(this).addClass('rotate-left').delay(700).fadeOut(1); $('.buddy').find('.status').remove(); $(this).append('<div class="status like">Like!</div>'); if ( $(this).is(':last-child') ) { $('.buddy:nth-child(1)').removeClass ('rotate-left rotate-right').fadeIn(300); } else { $(this).next().removeClass('rotate-left rotate-right').fadeIn(400); } });
.rotate-left transform: rotate(30deg) scale(0.8); transition: 1s; margin-left: 400px; cursor: e-resize; opacity: 0; z-index: 10;
「右に400px,30度傾けて80%の大きさに変更する」を1秒かけて行うという処理
transform: rotate(30deg) scale(0.8); transition: 1s; margin-left: 400px;
- transition: 1sがないと一瞬で動いてしまう
やっていること
- rotate-leftで要素を傾ける
- delayとfadeOutで少し遅らせてフェードアウト(hide)する
- スワイプイベントはhammer.jsを使っている
思ったこと
Tinderのように左右のスワイプはこれで実現できる。 ただこれだと毎回同じ見た目のスワイプになってしまうので、 Yentaのようにドラッグしてどこかに飛ばすということは出来ないなぁ