2017年1月23日 星期一

MailBox

參考網站 https://medium.com/@danamulder/tutorial-create-a-simple-messaging-system-on-rails-d9b94b0fbca1#.yi0myzbcv
自己練習過後的筆記
先從model開始,因為是要做mailbox,所以需要下面三個表單
  1. user <- user資料
  2. message <-所有訊息
  3. conversation <- 記錄哪些人和哪些人有建立過對話
一個user會有好幾個對話,一段對話會包含很多條message,而message則會隸屬於某段對話和使用者
class Conversation < ActiveRecord::Base
  belongs_to :sender, :foreign_key => :sender_id, class_name: 'User'
  belongs_to :recipient, :foreign_key => :recipient_id, class_name: 'User'

  has_many :messages, dependent: :destroy

  validates_uniqueness_of :sender_id, :scope => :recipient_id

  scope :between, -> (sender_id,recipient_id) do
    where("(conversations.sender_id = ? AND conversations.recipient_id =?) OR (conversations.sender_id = ? AND conversations.recipient_id =?)", sender_id,recipient_id, recipient_id, sender_id)
  end

end
上面建立了一個between scope,是為了之後方便確認某兩位使用者之間有沒有建立過對話
最前面兩個belongs_to是為了方便可以查到sender或是recipient的使用者資料,因為從sender_id或是recipient_id沒有辦法自動對應到關聯model,所以需要在後面指定class_name: ‘User’,然後直接寫明foreign_key
class Message < ActiveRecord::Base
  belongs_to :conversation
  belongs_to :user
  validates_presence_of :body, :conversation_id, :user_id

  def message_time
    created_at.strftime("%m/%d/%y at %l:%M %p")
  end
end
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
  has_many :messages
  has_many :conversations
end

conversation index
<div class=”ui segment”>
  <h3>Mailbox</h3>
    <div class=”ui list”>
      <div class=”item”>
        <% @conversations.each do |conversation| %>
          <% if conversation.sender_id == current_user.id || conversation.receiver_id == current_user.id %>
            <% if conversation.sender_id == current_user.id %>
              <% recipient = User.find(conversation.receiver_id) %>
            <% else %>
              <% recipient = User.find(conversation.sender_id) %>
            <% end %>
            <%= link_to recipient.first_name,   conversation_messages_path(conversation)%>
          <% end %>
        <% end %>
      </div>
   </div>
  </div>

<div class=”ui segment”>
  <h3>All Users</h3>
    <div class=”ui list”>
      <% @users.each do |user| %>
        <% if user.id != current_user.id %>
          <div class=”item”>
            <%= user.first_name %> <%= link_to ‘Message me!’, conversations_path(sender_id: current_user.id, receiver_id: user.id), method: ‘post’%>
          </div>
        <% end %>
      <% end %>
    </div>
</div>
mailbox的首頁,controller裡面已經定義好@users和@conversations會撈出所有的使用者和目前所有的對話,然後view在顯示出目前使用者相關的對話,以及可以send訊息的link,點下會連到conversation的create action
  def create
        if Conversation.between(params[:sender_id],params[:recipient_id]).present?
      @conversation = Conversation.between(params[:sender_id], params[:recipient_id]).first
    else
      @conversation = Conversation.create!(conversation_params)
    end
    redirect_to conversation_messages_path(@conversation)
  end
會先判斷這兩個使用者之間有沒有已存在的對話,有則把舊的撈出來,沒有就create,之後的動作會交給message controller
  def new
    @message = @conversation.messages.new
  end

  def create
    @message = @conversation.messages.new(message_params)
    if @message.save
      redirect_to conversation_messages_path(@conversation)
    end
  end

private
  def message_params
    params.require(:message).permit(:body, :user_id)
  end
Written with StackEdit.

2017年1月22日 星期日

Reverse String

https://leetcode.com/problems/reverse-string/
某次面試有被問到的問題,我忘記我當初寫怎樣了
不過有點像我在stack overflow上看到的
http://stackoverflow.com/questions/31171424/reversing-a-ruby-string-without-reverse-method
@string = "abcde"
@l = @string.length
@string_reversed = ""
i = @l-1
while i >=0 do
 @string_reversed << @string[i]
 i = i-1
end
return @string_reversed
然後被說很不ruby
老實說很多時候我腦中想的還是什麼i = 0 i>=5 i++之類的東西i++
總之我又重改了一次
def reverse_string(s)
    new_string = ""
    s.length.times do |i|
        index = (i+1)
        new_string << s[-index]
    end
    new_string
end
這樣有比較ruby一點了嗎orz
Written with StackEdit.

排序

泡沫排序Bubble Sort

def bubble_sort(list)
    list.each_with_index do |no|
        (list.length - 1).times do |e|      
            if list[e] > list[e + 1]
                list[e],list[e+1] = list[e+1],list[e]
            end
        end
    end
end

插入排序法(Insertion Sort)

 def insertion_sort(list)
        list.each_with_index do |no, index|
            (0..index).each do |i|
                if list[index] < list[i]
                    list[index], list[i] = list[i], list[index]
                end
            end
        end
    end

選擇排序(Selection sort)

def select_sort(list)
    (list.length - 1).times do |i|
        p "#{i} times fo #{list} and the mis is #{list[i..-1].min}"

        min_index = list.rindex list[i..-1].min
        if list[i] > list[i..-1].min
            list[i], list[min_index] = list[i..-1].min,list[i]
        end
    end
    list
end

Written with StackEdit.

temp

因為原來老師的架構和我自己想要的不一樣、所以做了以下修改
因為自動寄sms/email的服務基本上都需要付費才方便使用,所以我移除了那些功能
改成需要手動執行rake來新增AuditLog

  desc "Check if there are any overtime work didn't report"
  task check_overtime: :environment do 
    employees = User.where(type: nil)
    week_start = Date.today.beginning_of_week
    week_end = Date.today.end_of_week
    no_overtime_week = []
    employees.each do |employee|
      no_overtime_week = employee.posts.where(date: @week_start..@week_end)
      unless no_overtime_week.any?
        AuditLog.create!(user_id: employee.id, status: 0, start_date: week_start, end_date: week_end)
      end
    end
  end

防止同一員工同一個禮拜產生兩次auditlog

  validates :start_date, uniqueness: { scope: :user_id }

員工新增顯示沒有加班的weeks,但目前還沒有打算提供修改辦法

新增只要auditlog被新增之後,就沒辦法申請那一個禮拜的加班的限制

def check_audit_log
  user = User.find(self.user_id)
  my_audit_logs = user.audit_logs.where.not(end_date: nil)
  date = self.date
  duplicate = ""
  my_audit_logs.each do |log|
    if (log.start_date..log.end_date).include? date
      errors[:overtime] << "duplicate" 
      return
    end
  end

Written with StackEdit.


2017年1月11日 星期三

製作月曆

製作月曆來顯示相對應日期的文章(未完成)
railscast PRO #213+
老實說因為block我還不熟,有些東西實在不是很懂怎樣跑的囧
總之先看到哪就先筆記到哪
code: https://github.com/telsaiori/ckeditor_test/blob/calendar/app/helpers/calendar_helper.rb
view:
  <%= calendar current_date do |date| %>
    <% date_key = date.strftime %>
    <% if posts_by_date[date_key] %> 
      <%= link_to date.day, posts_path(posts_by_date: date_key) %>
    <% else %>
      <%= date.day%>
    <% end %>
  <% end %>
code:
def calendar(date = Date.today, &block)
  Calendar.new(self, date, block).table
end

 class Calendar < Struct.new(:view, :date, :callback)
     Calendar.new(self, date, block).table
 end
這裡使用Struct.new(:view, :date, :callback)和設定attr_accessor :view, :date, :callback效果是一樣的
然後把self: 本來網頁的view
date: 當日日期
block:本來view裡面的block丟給Calendar然後由table method建出月曆
delegate主要是用來讓A class也可以使用別的class的method,這邊的話就是讓Calandar裡面也可以使用content_tag這個helper
不然會出現
undefined method `content_tag’ for CalendarHelper::Calendar:0x007fb442119330
   class Calendar < Struct.new(:view, :date, :callback)
      HEADER = %w[ 日 一 二 三 四 五 六]
      START_DAY = :sunday

      delegate :content_tag, to: :view

      def table
        content_tag :table, class: "calendar" do
          year_header + header + week_rows
        end
      end
下面生成table的過程就比較單純
生成星期幾的部分,因為前面已經定義好HEADER,這邊只是把它變成[“日“, “一“, “二“, “三“, “四“, “五“, “六“]然後再靠join轉成字串在用html_safe讓他可以正常輸出到view
   def header
        content_tag :tr do
          HEADER.map { |day| content_tag :th, day}.join.html_safe
        end
      end
生成一個星期的row,先用一開始代進來的date算出這星期的第一天和最後一天,然後和上面一樣轉成html
def week_rows
    weeks.map do |week|
      content_tag :tr do
        week.map { |day| day_cell(day) }.join.html_safe
      end
    end.join.html_safe
  end


  def weeks
    first = date.beginning_of_month.beginning_of_week(START_DAY)
    last = date.end_of_month.end_of_week(START_DAY)
    (first..last).to_a.in_groups_of(7)
  end
中間會先把日期丟給day_cell處理
capture可以把模板保留成string方便之後在需要的地方處理
以這邊的view.capture(day, &callback)就是會把目前正在處理的日期回傳給view裡面的block
比方如果目前處理到“Wed, 11 Jan 2017”
如果沒有文章,capture的結果會是”\n 11\n”
有文章的話會得到
“\n      <a href=\"/posts?posts_by_date=2017-01-11\">11</a>\n”
 <%= calendar current_date do |date| %>  
    <% date_key = date.strftime %>  
    <% if posts_by_date[date_key] %> 
      <%= link_to date.day, posts_path(posts_by_date: date_key) %>
    <% else %>
      <%= date.day%>
    <% end %>
  <% end %>




 def day_cell(day)
    content_tag :td, view.capture(day, &callback), class: day_classes(day)
  end

  def day_classes(day)
    classes = []
    classes << "today" if day == Date.today
    classes << "notmonth" if day.month != date.month
    classes.empty? ? nil : classes.join(" ")
  end
Written with StackEdit.

ActionCable - An unauthorized connection attempt was rejected

試著照上課內容做,卻一直跳An unauthorized connection attempt was rejected
上網找了找只有這篇講的可以解決我的問題
但我還不知道原因,先筆記起來

def find_verified_user
      (current_user = env['warden'].user) ? current_user : reject_unauthorized_connection
 end
http://stackoverflow.com/questions/39438568/actioncable-failed-to-upgrade-to-websocket

2017年1月7日 星期六

O’REILLY COLLECTION

https://chogetsuku.jp/product/orecolle/

手機上有很多靠著不停狂click來進行的遊戲,最有名的應該就是cookie clicker

但最近我發現了更神經病的遊戲

O’REILLY COLLECTION



基本上就是個滿足你書架上滿滿他們家的書的夢想(?)的遊戲

你開始點螢幕的話,畫面上的工程師就會開始狂敲鍵盤(你可以設定鍵盤要是哪一種類型的鍵盤的聲音),如果一段時間沒有點螢幕的話,他會開始上網(基本上是看著貓)


錢湊夠了就可以去轉蛋了,書也是有分1~5星,雖然我不知道級別標準是甚麼





不過基本上他只有封面和基本介紹,和實際上的書並沒有相關聯,真的想看書還是要自己買,這遊戲就是給你一個夢想而已







2017年1月6日 星期五

rescue_from

之前網頁炸了就一直讓它顯示預設的錯誤畫面
這次想試著讓它顯示我想要顯示的樣子
http://apidock.com/rails/ActiveSupport/Rescuable/ClassMethods/rescue_from
#ApplicationController
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception

  rescue_from ActiveRecord::RecordNotFound, with: :resource_not_found

  protected

  def resource_not_found

  end
end
在ApplicationController加rescue_from,後面指定是哪一種錯誤的時候要用
因為這次是要修改ActiveRecord::RecordNotFound in ArticlesController#show這一種錯誤的行為,所以後面接的事ActiveRecord::RecordNotFound
resource_not_found留白是因為可能之後不同controller可能會想要有不一樣的動作,所以不在application controller裡面寫死,改寫在目標的controller裡面
#article.rb
  protected

  def resource_not_found
    message = "The article you are looking for could not be found"
    flash[:alert] = message
    redirect_to root_path
  end
這樣子如果在網址列輸入http://localhost:3000/articles/xxxx這種不存在的id的時候會改轉跳到root頁面,並且顯示flash
Written with StackEdit.