aws step function 筆記

最近工作用到一些工具,使用到AWS step function , 因此在這裡也筆記一下…

也在公司後端組例會分享了一下(以下就是我分享的PPT ):

其實我覺得我用的情境很簡單,只是用Map 的方式啟動lambda . 這個 lambda 就是我用來處理下載與上傳到s3指定位置… 說真的應用的情境真的很不多… 還有更多著墨的空間。

另外,自己同時也針對此寫了兩個版本,用SAM 和 用 CDK 的版本…

一、CDK 的版本

import * as cdk from '@aws-cdk/core';
import * as lambda from "@aws-cdk/aws-lambda"
import * as stepfunctions from "@aws-cdk/aws-stepfunctions"
import * as tasks from "@aws-cdk/aws-stepfunctions-tasks"
import * as logs from "@aws-cdk/aws-logs"
import * as s3 from "@aws-cdk/aws-s3"
import * as ec2 from "@aws-cdk/aws-ec2"
import * as dotenv from 'dotenv';

export class CdkLambdaStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // 將裡面比較敏感的資訊用env 包起來, 注意後面的path 要正確
    dotenv.config({path:__dirname+'/../.env'})
    
    // 我要上傳音檔的S3 目標 arn:aws:s3:::test 為虛構(我忘了把這個也包env了哈哈)
    const bucket = s3.Bucket.fromBucketArn(this,"test","arn:aws:s3:::test")

    // 負責前面呼叫step function 的 lambda
    const downloadAudioLambda = new lambda.Function(this, "downloadAudioLambda", {
      runtime: lambda.Runtime.NODEJS_12_X,
      timeout: cdk.Duration.seconds(25),
      handler: "index.handler",
      code: lambda.Code.fromAsset("lambda/downloadAudioLambda")
    });

    bucket.grantPut(downloadAudioLambda)

    const downloadAudioJob = new tasks.LambdaInvoke(this,'Calllambda',{
      lambdaFunction: downloadAudioLambda,
      outputPath: "$.Payload"
    })

    const map = new stepfunctions.Map(this, 'ExampleMapState');
    map.iterator(downloadAudioJob);

    const logGroup = new logs.LogGroup(this, 'StepFunctionLogs')

    const stateMachine = new stepfunctions.StateMachine(this, 'StateMachine', {
        definition: map,
        logs: {
          destination: logGroup,
          level: stepfunctions.LogLevel.ERROR
        }
    });

    const testVpc = ec2.Vpc.fromLookup(this,"vpc-dev",{
      vpcId: process.env.VPCID
    });

    const processorLambda = new lambda.Function(this, "processorLambda", {
      runtime: lambda.Runtime.NODEJS_12_X,
      handler: "index.handler",
      timeout: cdk.Duration.seconds(25),
      code: lambda.Code.fromAsset("lambda/processor"),
      vpc: testVpc,
      environment: {
        ENDPOINT: process.env.ENDPOINT ?? 'localhost',
        DATABASE: process.env.DATABASE ?? 'db',
        DBUSERNAME: process.env.DBUSERNAME ?? 'root',
        PASSWORD: process.env.PASSWORD ?? 'password',
        NODE_ENV: process.env.NODE_ENV ?? 'test',
        statemachine_arn: stateMachine.stateMachineArn
      }
    });

    stateMachine.grantStartExecution(transferLambda)
  }
}

總之,上面我就是用CDK先創建我的lambda , 然後把那個要放到state machine 的建立”task”, 給予我另外一個lambda 有 startExecution 的權限…. 簡單完成!

二、SAM 的版本

總之,有些原因,我另外又學習怎麼用SAM製作 state machine XDD

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description:
  download audio file from huaxi to trigger audio transcoder
Resources:
  ProcessAudioFileStateMachine:
    Type: AWS::Serverless::StateMachine # More info about State Machine Resource: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-statemachine.html
    Properties:
      DefinitionUri: statemachine/audioFile_processer.json
      DefinitionSubstitutions:
        DownloadAudioFunctionArn: !GetAtt DownloadAudioFunction.Arn
      Policies: # Find out more about SAM policy templates: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-policy-templates.html
        - LambdaInvokePolicy:
            FunctionName: !Ref DownloadAudioFunction

  DownloadAudioFunction:
    Type: AWS::Serverless::Function # More info about Function Resource: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html
    Properties:
      FunctionName: downloadaudio
      CodeUri: functions/downloadaudio/
      Handler: index.handler
      Runtime: nodejs12.x
      Timeout: 20
      Policies:
        - S3ReadPolicy:
            BucketName: 'test'
        - S3WritePolicy:
            BucketName: 'test'

  ProcessorFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: processor
      Timeout: 20
      CodeUri: functions/processor/
      Handler: index.handler
      Runtime: nodejs12.x
      Environment:
        Variables:
          ENDPOINT: db_url
          DATABASE: dbname
          DBUSERNAME: dbusername
          PASSWORD:dbpassword
          NODE_ENV: test
          statemachine_arn: !Ref ProcessAudioFileStateMachine
      Policies:
        - StepFunctionsExecutionPolicy:
            StateMachineName: !GetAtt ProcessAudioFileStateMachine.Name

其實說真的CDK 和 SAM 沒有多大差別,只是CDK你可以用比較程式化的去做那個state machine language (就是sam 裡面要包的那個json 啦!),像我,實在懶得去構想那個json 怎麼寫(啊我就不是JSON工程師啊~),所以先用CDK 產生state machine , 然後上AWS控制台上面把那一串json 抓下來,放到我的sam 這裏… 整理一下,CDK detroy 一下,sam 的template.yaml 調整一下,一個下午搞定啦!(不過我好像忘了在sam 裡面宣吿log 去接state machine 啦 XDDD 之後再研究吧!)

小君曰:還有很多成長的空間

Pytest 簡單教學

最近在整理自己的履歷和side projects……,順便也買了一些線上課程學習,其中有一門課是教你演算法,舉Leetcode 裡面的題目為例,如果再工程師界久了都知道,Leetcode 是一個刷題網站,而我身為想要變強的工程師當然不可以忽略這個網站啊…… 因此在bitbucket 開了一個專案,放置一些藉由上課所學習的解題檔案(線上課程用的是JAVA),但我想要轉成Python ,藉此提升自己的python實力~~

如果有興趣可以來看看,但因為目前上課進度緩慢,其實也才幾題而已XD https://bitbucket.org/r567tw/leetcode/src/master/

不過在本機跑的時候也想要自己就先在本機測試一下不要用leetcode 在那邊幫我測試…但之前都是用類似以下的語法

test = Solution(); #先new 一個Solution 的class
print(Solution.method(...)) #然後呼叫方法一個一個用肉眼檢查

這種方法超級土法煉鋼的… 完全就不是工程師的style ~~

而我是一個php工程師,之前花了一點時間了解phpunit , 然後也有在一些專案寫一些UnitTest… 心想…. 難道python 沒有嗎?

叮咚! 原來就是Pytest 啊! 我現在leetcode 刷題要在本機測試都會使用這個來玩玩看的!接下來我要介紹怎麼使用Pytest,以及我如何將這個導入到我這個leetcode 的練習專案。

安裝Pytest

首先你要使用pytest 之前就一定要確認pytest 有沒有在你的電腦當中(廢話!),所以你可以參考這個文件來幫助你安裝pytest ,其實也就這麼簡單

$ pip install pytest

然後其實很簡單,就是使用pytest 這個指令或者pip freeze 確認pytest 在不在就好了啊

使用Pytest

其實和phpunit 很像,其實也是用所謂“assert”的方式確認答案是否正確,以底下程式碼為例說明:

from solutions.atoi import Solution


def test_myAtoi():
    test = Solution()
    assert(test.myAtoi("42") == 42)
    assert(test.myAtoi("   -42") == -42)
    assert(test.myAtoi("4193 with words") == 4193)

其實Pytest 的部分就是去偵測你的個函數名稱是否前綴有個`test` ,如果有的話就會跑底下的內容,於是一個完美個TDD流程完成!

接下來就是跑個指令、然後看看結果就好了,以我目前很緩慢只有解Atoi\Palindrome\Pow 的狀況就像底下的情況一樣

alindrome

$ pytest
============================================= test session starts =============================================
platform darwin -- Python 3.6.4, pytest-3.3.1, py-1.5.2, pluggy-0.6.0
rootdir: /Users/fang/playground/leetcode, inifile:
collected 3 items                                                                                             

tests/test_atoi.py .                                                                                    [ 33%]
tests/test_palindrome.py .                                                                              [ 66%]
tests/test_pow.py .                                                                                     [100%]
========================================== 3 passed in 0.05 seconds ===========================================

你寫幾個測試檔案,裡面就會有幾個items ,如果你最後沒看到什麼failed 的話就表示你都很順利喔~

剩下的我就利用一些modulte 引入的概念,將資料夾很清楚分出tests 和 solutions ,之後我就在solutions 裡面放入leetcode 這題的解法,而tests 裡面放的就是要被驗證的結果,沒過pytest 就會告訴我沒過了

小君曰:之後要參加鐵人賽了,就決定暫時不繼續努力週更了XD

 

VS-code 的炫炮神器-power mode

在某一天我看到某個人做一個程式的直播,教大家怎麼去爬蟲成人影片….. 以下我附上影片:

直播主滿滿的歡樂與搞笑啊哈哈,然後我發現他寫code 時會有一些震動與火花… 呵呵 感覺很有趣,後來查一查好像是外掛所處理的部分,發現原來Atom 有一個外掛power mode 也是可以達成類似的效果…想一想,Atom有了VS-Code會沒有嗎? 把「power mode」這個關鍵字放到vs-code的外掛搜尋列上,果然找到了!

同場加映: 我覺得有時候寫程式也可以解決自己的問題,有位youtuber 也分享了關於一些網頁的「暗黑技巧」,其中我覺得playbackrate 這個參數實在是太好用了啦…

小君曰:「這power mode 超級炫炮的啦....」

Laravel Tinker 一行就退出的問題

最近使用laravel ,發現遇到一行就退出的問題,發現原來是php 7.3 的問題… 詳細資源請參考:https://learnku.com/laravel/t/21165

解決方案

建立 ~/.config/psysh/config.php 這個檔案

然後在這個檔案裡面寫道

<?php
return [
  'usePcntl' => false,
];

之後就解決了這個一行就退出的問題囉~

Pytube 簡單教學

來寫個簡單的python 教學好了,對了! 去年我有挑戰it 幫鐵人賽,參加的是自我挑戰組,並且自己訂的主題就是python 30天! 歡迎大家去看看!

連結於此

對於鐵人賽完賽的心得不必多說,我想已經都寫在最後一天了,總之就是覺得自己還有很大的成長空間,下次參加鐵人賽一定要有更充足的準備和題目。

不得不說,這次鐵人賽的獎品
我個人覺得好浮誇……

好了,簡單交代近況也夠了,進入主題來談談python 好用的套件pytube 吧!

pytube 是用來可以抓youtube的影片,首先,你必須先安裝它

$ pip install pytube

接下來你可以確認一下pytube 是否正常運作?

$ pytube --version
$ pytube 9.4.0

注意:

如果你是最新安裝pytube version 應該會是9.5.1 , 不過pytube 9.5.1 有些問題,可以參考此連結解決問題

接下來我們就可以開始寫下載youtube影片的程式啦!
這裡我只是簡單呈現怎麼撰寫,詳細與延伸可以參考文件:https://python-pytube.readthedocs.io/en/latest/#
小君曰:不知道為什麼文件的版本似乎落後了我目前寫的版本…

# 就是這麼簡單!!!!
from pytube import YouTube

url =input('請輸入你要下載的youtube網址: ')
print('下載 來自'+url+' 的youtube影片中...')
YouTube(url).streams.first().download()

像我自己想要更加炫技一下就會想知道我目前youtube影片的名字的話可以這樣寫….. 加入beautifulSoup 這個可以分析網頁的套件。

from pytube import YouTube
import requests
from bs4 import BeautifulSoup

url =input('請輸入你要下載的youtube網址: ')

# 先去youtube 上看看這部影片的名字
request=requests.get(url)
context = request.content
# 藉由BeautifulSoup
soup=BeautifulSoup(context,"html.parser")
# 取得我要的資料
video_name = soup.select('h1.watch-title-container')[0].get_text();
# 資料清理
video_name = video_name.replace('\n','')
video_name = video_name.replace(' ','')
# 準備下載啦
print('下載 來自'+video_name+' 的youtube影片中...')
YouTube(url).streams.first().download()
print('下載完成!')

Python_Virtualenv 簡單筆記

前言

有點xx 久沒有寫文章了…
這次來筆記一下python virtualenv~ 一個使用不會污染原本python package 的東西~ 有點類似虛擬環境的概念。

雖然後來發現…python 3 好像也有提供自己的virtual env… 指令是“python3 -m venv {這裡放置的是你要的環境名稱}”,然後要啟動他其實和關閉它其實和vituralenv 有點差不多…

Notice: 以下我使用的環境都是for Mac , 如果你是其他作業系統可以參考但請查閱文件

安裝

不多說,安裝pip 後請服用

pip install virtualenv

然後確定是否有安裝成功請服用

virtualenv --version

如果有出現一串數字那就表示可以用啦!如果有安裝上的錯誤請自行google, 或者在底下留言,有空的話我可以幫忙trace 一下啦,順便一起成長~

使用

1.創造虛擬環境

virtualenv {接你想接的任何環境名稱}
舉例來說: virtualenv testenv

然後等他跑一下你會看到目錄下有個被你指定的名稱資料夾,以例子來看就是testenv資料夾,裡面大概長這個樣子

PS. 以下我都會用testenv這個資料夾名稱作為範例,你們要使用請將testenv換成任何你們想換的資料夾名稱呦

testenv
├── bin
├── include
├── lib
└── pip-selfcheck.json

Tips: 上面這麼完美的一個資料夾樹是我用tree 這個指令做的,使用“tree -L 1 testenv” , 你可以用brew 安裝tree 之後應該就可以服用,L是一個參數,你可以在後面輸入數字選擇你想顯示的資料夾階層數目

2.啟動虛擬環境
請服用

source testenv/bin/activate

接下來你會看到你的command line 最前面有(testvenv) 的字樣(或者任何你設定的資料夾名稱)

Tips: 小弟查過關於source 這個指令的傳說,就是將執行的指令檔裡面所設的參數或者內容應用到整個command line 環境中…

像是:

(testenv) xxx@xxx-MacBook-xxx-$

3.離開虛擬環境
已經在虛擬環境中如果想離開請用

deactivate

沒錯!就是這麼簡單

4.其他你可能在虛擬環境裡有幫助的指令們
– 查python或pip 安裝的版本

python --version
pip --version
  • 查看pip 安裝了哪些modules
pip freeze
  • 將pip 安裝的modules 紀錄,這樣以後才能讓別人一鍵安裝
pip freeze > requirements.txt
  • 藉由別人提供的紀錄安裝python module
pip install -r requirements.txt

幕後花絮

一般來說用vituralenv 創造的python 版本都會是python 3以上,但如果今天我要python 2呢?(雖然python 2 已進入倒數)

virtualenv {你的資料夾名稱} --python=python2.7

P.S. 請確定你有裝python2.7 或你指定的版本喔…另外聽說也可以使用pythonbrew 解決這個情況…不過小弟試過好像有點卡關可是我也沒有面對要python多版本的部分所以就果斷放棄

剩下的我都放在文件裡了,好啦也不是我寫的文件,有關於virtualenv的其他使用或進階用法可以參考這個文件

小君曰:還是多寫寫文章增加自己的實力好了

使用Laravel-Valet 安裝Magento

前言

因為最近工作要用到以及學習Magento2,所以我必須先試試看在Local 端安裝一個基礎款的,以便日後可以學習。而我自己也有在學習Laravel,得知Mac 有個好用的工具叫做Valet ,可以不用設定什麼etc/host 之類的就可以有一個測試的網址然後連過去(壞處就是必須自己的Local 端要先安裝好php和mysql ,valet 只是幫你把網址與資料夾名稱掛上去而已喔)

Notice. Valet 只能for Mac喔

安裝Valet

這我就不多說太多了哈哈(明明就是自己懶得說…
你可以參考文件
我這裡粗略的帶一下,在之前請確定你有安裝php 和mysql

composer global require laravel/valet
valet install
//移動到你想要做的資料夾
valet park

這樣之後你的資料夾底下如果有哪個子資料夾,你就可以直接在瀏覽器打上“http://{資料夾名稱}.test” 就可以無痛使用囉

安裝Magento2

因為valet 是laravel 出來的,所以對laravel 蠻友善的,他在官網有列出支援Magento,但我實際上在用還是有點卡卡的,所以在這裡也記錄一下我的痛點造福各位

composer create-project --repository=https://repo.magento.com/ magento/project-community-edition <install-directory-name>

我這裡為了等等教學方便 install-directory-name 會替代為Magento2,如果你要用的話可以將Magento2 取代為任何你想要的名稱

然後你以為你連Magento2.test或者Magento2.test/setup 就可以用瀏覽器安裝了嗎? 呵呵 這就是痛點所在,不好意思請移到你安裝的資料夾底下使用”command-line” 建立喔

php bin/magento setup:install
--backend-frontname="admin"
--db-host="localhost"
--db-name="magento_2_db"
--db-user="root"
--db-password="root"
--base-url="http://magento2.test/" --base-url-secure="https://magento2.test/"
--admin-user="admin"
--admin-password="admin123" --admin-email="pramod.kharade@example.com" --admin-firstname="Pramod"
--admin-lastname="Kharade"

Notice: 那個db-name db-host等等和db 有關的我只是範例喔,要使用時請務必替換成你自己本機的名稱,然後啊我這裡只是為了排版好看讓你們看,要輸入給command line 的時候請不要換行,確認– 到下個– 只有一格空格,這樣才會成功喔

呼…. 連入https://magnento2.test ,就可以看到畫面了…

安裝Magento1

請到這裡
然後到“release archive” 這個tab 找到Downloader – 1.x 的部分
選擇你可以解壓縮的版本並將他下載下來,放到你要安裝Magento1 的資料夾當中(我這裡資料夾名稱範例是Magento1),然後用瀏覽器打上”http://magento1.test/downloader.php” 就可以看到Magento1 的安裝畫面囉,然後自行設定一下就好囉

後記

最近又突然想把techblog 從october CMS 轉回Wordpress 了哈哈,可能趁著這個中秋連假來幹這些事情好了哈哈

laravel -深入 migration筆記

資料庫的設定

  • 修改env 檔
...(略)
DB_CONNECTION={填入你的db 類型}
DB_HOST= {填入你的db server}
DB_PORT={填入你的db server port}
DB_DATABASE={填入你的db name}
DB_USERNAME={填入你的db user name}
DB_PASSWORD={填入你的db password}
...(略)

關於migration 的指令

php artisan make:migration {name} (--create={table}/--table={table})
php artisan migrate # 執行migrate
php artisan migrate:rollback #恢復上一版本得migration
php artisan migrate:reset #重新reset
php artisan migrate:refresh #重新建立
  • 補充:除了make migrate 的指令其他都可以在加入 –seed 以順便一起跑seeder

Ruby 筆記

Ruby基礎

變數與輸入輸出

puts 'Hello World' #output Hello World
puts 20+2 #output 22
puts 20-2 #output 18
puts 20*2 #output 40
puts 20/2 #output 10
name='John' #no output
puts name #john
name=gets.chomp #get user input
puts 'Hello'+name #output Hello John
print 'Hello world' #不會換行 output Hello World
  • puts 印出資料 (換行)
  • print 印出資料(不換行)
  • gets.chomp 取得輸入
  • + 將兩個文字串接

  • boolean: true 和 false

Tips:
\= 指派相等
\== 比較是否相等
!= 比較是否不相等

irb

  • irb 是一個ruby 的命令介面,可以即時執行ruby 結果
  • control+l 清空
  • exit 離開

if …else…end

  • # 註解
#number =8
number = Random.rand(9)
#隨機產生0-9 的數字
print("請猜一個1~15之間的數字")
guess=gets.chomp.to_i
#to_i 轉換為數字

if guess == number # '8' != 8
puts '猜對了,答案是'+number.to_s
#to_s 轉換為字串
else
puts '猜錯了!'
end

while…end

#上一個的進階版
number = Random.rand(14)+1
#while guess==number #迴圈
while true
print("請猜一個1~15之間的數字")
guess=gets.chomp.to_i
if guess == number # '8' != 8
puts '猜對了,答案是'+number.to_s
break;
else
if guess &gt; number
puts '猜錯了! 太大了'
else
puts '猜錯了! 太小了'
end
end
end

Array

scores= [80,100,90,99] #定義一個名為scores 的array
scores.each do |score|
puts score
end
#另外一種寫法
scores.each {|score|puts score}

print(scores[0]) ## 印出第一個ruby array 值
print(scores.pop(2)) ## 教最後兩個叫出來 [90,99]
print(scores.pop) # 將最後一個叫出來 [99]
print(scores.sort) # 排序 [80,90,99,100]

成績管理程式-綜合應用

# 1=&gt;檢視成績 2 新增成績 3 刪除成績 4 結束成績
scores=[90,88,85]
puts '輸入 1 檢視成績、2 新增成績、3 刪除成績、4 結束程式'
while true
print '&gt;'
command = gets.chomp.to_i

if command == 1
scores.each do |score|
puts score
end
end
if command == 2
print '請輸入要新增的成績:'
scores.push gets.chomp.to_i
end
if command == 3
print '請輸入要刪除的成績位置:'
scores.delete_at (gets.chomp.to_i-1)
end
if command == 4
puts '程式結束!'
break
end
end

Hash

record={'name'=&gt;'john','score'=&gt;90}
records={:name=&gt;'john',:score =&gt;90}

puts record[name] #john
puts record[score] #90

puts records[:name] #john
puts records[:score] #90

record.each do |key,value|
puts key
puts value
end
````

## method
```ruby
def greet
puts 'hello'
end

greet #=> hello
#def method_name....end
def greet(name)
puts 'hello,'+name
end

greet 'John' #=> hello,John

require_relative 'method' #引入該資料夾底下的method.rb
</code></pre>

<h2>object</h2>

<ul>
<li><em>在ruby 世界中 任何東西都是一種物件</em></li>
</ul>

<pre><code class="language-ruby">class Robot
attr_accessor :power,:score...
def initialize(power,score)
@power - power
@score = score
end
def move_forward
# @power
puts '往前走'
end
end

robot1 = Robot.new 1.0
robot2= Robot.new 2.0
robot1.move_forward # 往前走

class Robot < Things //< 代表繼承 attr_accessor :power,:score... def initialize(power,score) @power - power @score = score end def move_forward # @power puts '往前走' end end ``` ## gem &gt; gem -v
> eg.gem install colorize
> **gem 安裝套件是裝在機器裡面的而非單個資料夾**

## Ruby on rails
### scaffold 指令

```bash
rails generate scaffold record title:string cost:integer
rails db:migrate
</code></pre>

<h3>terminal 終端機命令複習</h3>

<pre><code class="language-bash">mkdir 創建資料夾
cd 移動
touch 創建檔案
rm 檔案名稱
//tab鍵 可以補齊
rmdir 移除資料夾
rm -rf test* 移除test 所有子資料夾
</code></pre>

<h3>rails 指令</h3>

<ul>
<li>rails new static-app</p></li>
<li><p>rails s (-b $IP -p $PORT)(C9 特殊設定)</p></li>
<li><p>c9 website: https://first-c9-r567tw.c9users.io/</p></li>
<li><p>rails controller 生成</p></li>
<li>rails g controller pages</li>
<li><p>在app/controller 底下會出現pages_controller.rb</p></li>
<li><p>rails route
-在config /routes.rb</p></li>
<li>route 寫法</li>
</ul>

<pre><code class="language-ruby">get '/about' => 'pages#about' //進入about 路由後啟動pages_controller.rb 裡的about function

class PagesController < ApplicationController def about #render plain:'hello wolrd' render file:'pages/about' #去找views/pages 裡的about.html file ->預設從views 資料夾為起點
#如果有依照命名慣例,甚至只要有def..end 就好 裡面空空沒關係
end

def index
#直接找pages 底下的index.html
end
end
</code></pre>

<ul>
<li>rails views
在app/views 資料夾裡</li>
<li>命名規則</li>
<li><p>PagesController 裡面的about 方法=> 將檔案建立在views>pages>about.html</p></li>
<li><p>layout 部份</p></li>
<li>在view/layout/application.html.erb 將layout 統一定義起來</li>
<li><p>在 app/assets/application.css 定義引入的css</p></li>
<li><p>gem=> 安裝Ruby 的套件</p></li>
<li>yarn => 安裝 js,css 等前端的套件</li>
<li>引入外部css 與js</li>
<li><strong>在app/assets/application.css require</strong></li>
<li>從node_modules 開始算</li>
</ul>

<pre><code>*= require bulma/bulma
</code></pre>

<ul>
<li>erb 就是一個可以在html 寫ruby 語法的附檔名</li>
</ul>

<pre><code class="language-ruby"><% #ruby...... %>
<%= 將ruby 語法執行完在貼回去 %>
# 只要在controller 裡的方法宣告資料 例如 @data=....
# 也不用特別render (除非是特別不按照命名慣例)
# 就可以在前面使用 <%= @data %> 把資料印出來
# each 用法
<% @datas.each do |data| %>

<%=data %>

<% end %>
</code></pre>

<p>補充
<%= 'is_active' if current_page?'/' %>

<ul>
<li>rails model
> rails g model store</li>
</ul>

rails db migrate

<pre><code class="language-ruby"># db/migrate/....create_stores.rb
class CreateStores < ActiveRecord::Migration[5.1] def change create_table :stores do |t| t.string :name #建立一個name 的字串欄位 t.string :description t.string :phone t.timestamps end end end ``` &gt; 執行 rails db:migrate
[migration 教學](http://guides.rubyonrails.org/active_record_migrations.html)
> rails console //類似 php artisan tinker
- activeRecord 模式 #store 為model name 可替換
- Store.new / store.save
- Store.create
- Store.all
- Store.find
- store.update
- store.destroy

### Ruby-rails-Form
```ruby
#表示json 格式輸出
render json:params
#csrf_token token
<input name="authenticity_token" type="hidden" value="<%=form_authenticity_token%>" />
  • create
def create
store = Store.new
#<input name="store[name]" type="text" />
store.name = params[:name]
# store.description = params[:description]
# store.phone = params[:phone]
# store.address = params[:address]
store = Store.new store_params

#store.save

redirect_to '/stores'
#redirect_to stores_path
end

private
def store_params
#設定欄位的白名單
params.require(:store).permit(:name, :description, :address, :phone)
end
end

補充:<% truncate store.description, length:20 %>

rails routes 指令 列出route 的別稱及路由

  • form helper
<% form_for Store.new do |f|%>
<% f.label :name,'店家資訊' %>
<% f.text_field :name %>
...(略)
<% f.submit '送出' %>
<% end %>
  • read/show

route: get ‘/stores/:id’ => ‘stores#show’

def show
@store = Store.find params[:id]
end
  • update
    route: get ‘/stores/:id/edit’ => ‘stores#edit’
    route: patch ‘/stores/:id’ => ‘stores#update’
# <%= link_to edit_store_path(store),class: 'button is-small is-primary is-outlined is-edit' do %>
def edit
@store = Store.find params[:id]
end
#<%= form_for @store do |f| %>
def update
@store = Store.find params[:id]
@store.update store_params
redirect_to stores_path
end

*補充 partial html==> render ‘name’ => _name.html.erb
– delete
route: delete ‘/stores/:id’ => ‘stores#destroy’

#<%= link_to 'delete', store_path(@store), method: :delete, data: { confirm: '確定要刪除嗎?' } %>
def destroy
@store = Store.find params[:id]
@store.destroy

redirect_to stores_path
end
  • 慣例及優化
    route: resource :stores
    before_action :set_store,only:[:show,:edit,:update,:destroy]
def set_store
@store=Store.find params[:id]
end
class Store < ApplicationRecord
validates_presence_of :name, :phone, :address, :description
# validates :name,presence:true
# validates :phone,presence:true
end
#in stores controller
if @store.save
redirect_to stores_path
else
render 'new'
end
  • 顯示錯誤資訊
<% @store.errors.full_messages_for(:phone).each do |msg| %>
<p class="help is-danger"><%= msg %></p>
<% end %>
  • 上傳圖片
    外掛使用:https://github.com/carrierwaveuploader/carrierwave

migration -> uploader 生成-> 與model activerecord 連結->controller 加入白名單->調整form 上傳等~

  • relationship
  • bcrypt gem 外掛–>加密
  • devise gem 外掛 ->>登入登出
  • cocoon gem 外掛 -> 可以動態新增表單的東西

  • 使用者故事

  • trello
  • 主詞
  • 可以做甚麼
  • 流程
  • 開發的流程
  • todos
  • test
  • coding
  • code review
  • staging 初步測試
  • production

  • 下一步

  • introduction to programming with ruby
  • rails guild
  • ruby on rails 實戰聖經
  • 為自己學ruby on rails
  • rails casts
  • rails go

Laravel 使用心得:用laravel 做一個超簡單的文章CRUD

最近因為工作,嘗試使用Laravel 更新我目前手上的專案網站。恩……這陣子使用心得有二
(1) 真的好好用阿
(2) laravel 真是博大精深,因為用一套framwork 就要跟隨那一套framework的規則走,有時候都覺得laravel 怎麼可以設計得這麼活!!! 原來還可以這樣寫XDDD

關於小弟的PHP旅程

小弟一開始,是認識到CMS,從而知道當時算是CMS界的霸主(不知道現在還是不是XD)–WordPress! 當時使用著使用著,還蠻方便的!! 而不知道為甚麼,可能我真的很喜歡寫程式使然~ 記得一開始入坑是因為一支很屌的Yahoo 即時通整人程式(哈哈 超屌的!! 我都覺得厲害),加上小弟讀資料處理科,當時學習的是Visual Basic,而且學的還不錯 ,基於被整就要整回去的「報復心態」,開始從整人程式起家…….寫一些讓電腦關機、無限迴圈等等超無聊的小把戲….到了大學讀資管系,有一陣子荒廢了這部分…..直到某個時候wordpress ,也不知道為甚麼的,居然開始撰寫wordpress 佈景主題,小弟寫了兩套,分別是 FangJRdesigner 和本站所使用的JimmyFDesginer 說真的,前面那一套我已經懶得更新了,或許後面這一套會持續在更新(畢竟是本站在使用的,小弟也不知道會不會有空XD) ,漸漸的,我學習及撰寫PHP 純Script 已經好一段時間,當然這段期間也因為CMS界打滾認識到Jommla 和Drupal 等用php 所寫的cms,但最後我還是選擇用Wordpress 架站。

這幾年藉由認識到Hahow 這個募資課程網站,正好有人在教Laravel ,說來也巧小弟也存了一些錢,加上早以心儀framework已久(一直苦於沒有師傅領進門以及沒有恆心毅力學習),後來就馬上買了那門課程,在上課的過程,發現Laravel 的好用之處以及為甚麼大家都這麼推framwork~~~

但是聽得看得都比不上實際做的,說真的最近才有時間去用laravel 更新我的專案,藉由實做的過程中,漸漸得認識到底甚麼是MVC 到底甚麼樣的方式可以寫讓人看得懂得程式。 最近因為一些工作上的挫敗以及最近在學Laravel 漸漸體認到 雖然解決問題很重要,但要寫出一個讓人看得懂得程式碼及有藝術的程式碼也是很重要的!

使用Laravel 做一個超級簡單的部落格

對我來說,如同前面我寫的文章(傳送門),不過建議大家還是要對於php 物件導向有個簡單基礎的認識,這樣才大概比較了解我所寫的(可能也不會?!),這裡不做太難的東西,就單純對文章的CRUD而已,以及使用者的登入登出…..兩個表:User 和 Post

DB migration

Laravel 的設計者真的很聰明,以前我從沒想到,原來db schema 是可以帶著走的,而且藉由env的設計,就算上傳了git 只要我不上傳真正的env(保護自己的資料),藉由一些簡單的步驟 也可以無痛轉移! 真的超強!

首先,我們必須先新增一個migration 檔

php artisan make:migration create_post_table --create=posts

只要下了這個指令就可以做一個create db table schema,接下來你只要在database 資料夾下migrations 底下
[日期時間戳記]_create_post_table.php 定義好你要的欄位,請參考以下網址,這樣,你就很簡單的下一條指令
php artisan migrate

如果你在env 對db的連線夠正確的話,應該會很成功的在你的資料庫看到你定義的東西
如果有噴錯的話請不要害怕(解決之道在此),google 和 stackoverflow會是你的好朋友,由於篇幅及小弟太懶就不在此贅述了

再來,我們必須定義文章的db schema,在 up function 裡面定義

我是寫這樣的

Schema::create('posts', function (Blueprint $table) {
     $table->increments('id');
     $table->string('title'); //文章標題
     $table->text('content'); //文章內容
     $table->timestamps();
});

接下來,在下 php artisan migrate 就可以了,你應該可以在你的database 看到post table

使用者的登入登出

太沒想到了! Laravel 居然可以這麼輕鬆的做到使用者登入登出還加上了註冊!! 一條指令就能解決

php artisan make:auth

接下來在你的controllers 和 view 及model 都會出現一些小變化哦~ 可以去看看

如果想要擋有使用者的輸入輸出可以用middleware !!!

MVC

mvc 其實說明非常的複雜,我的理解是 Model 是對於資料庫的”連接層”;Controller 處理過程的邏輯;View 則是頁面上的呈現

laravel 製作mvc的指令分別如下
php artisan make:controller [controller_name]
(–resource) 加上resource 可以將laravel 原生的資料庫CRUD function 都會幫你宣告進去,至於要製作model 指令為

php artisan make:model [model_name]

最後 view 的部分 請在view 的資料夾 裡新增 [view_name].blade.php 吧! 你必須先學會一點blade 語法,可以幫助你撰寫laravel 的 view。

關於資料的CRUD

Laravel 對資料的CRUD 採用了ORM 的方式,我簡單來說就是使用物件的方式管理資料庫
如同前面我寫有關於資料的CRUD ,用純PHP 的方式我們必須同時也要了解SQL語法,這還不打緊,一不小心寫錯了SQL語法….還會噴一堆錯誤Trace code trace了半天

關於詳細得CRUD 我覺得Laravel 的文件其實也寫的很清楚,歡迎去翻閱看看

首先,前面我說過MVC的架構,在Laravel 就是使用這樣的架構,所以我們先建立與資料庫密切相關的Model

php artisan make:model Post

接下來你就會看到在App 資料夾底下會有一個 Post.php。

Laravel 很聰明,為了防止別人惡意的大量新增,所以我們必須先設計哪些欄位可以做大量賦值的動作。在Post.php  class 裡增加這一句話:

protected  $fillable= [
     'title', 'content'
];之後,要建立controller 與model 串連
php artisan make:controller PostController --resource
接下來你就會在app/Http/Controllers/ 看到PostController.php
MVC 的架構讓我們在實做文章的增刪改查上會有點複雜和麻煩,但好處是可以分隔所謂的邏輯和頁面。
在PostController.php 最上面先宣告使用的Model –> Use App\Post;
接下來就進入CRUD 的邏輯世界了,我這裡簡單的寫一下,可以的話請直接參考這裡
並且還要注意REST_ful URL 的規則,REST_Ful URL 就是將網址做為一個可以執行操作的工具,例如下”url/$id”,就會去索取 id 為 $id 的url 實體,藉由URL 的樣式我們可以做像database 的操作感覺。(說的那麼爛,有請wiki 大神救援)
總而言之,在Laravel 裡有個Routes 的資料夾,分別有api.php web.php 等等檔案,有點類似說要定義laravel 這個程式該”怎麼走”,例如post/ 就會到post 的首頁,要把post 裡所有的資料都列出來。
之後請在Routes/web.php 裡面添加這一行:
Route::resource('post', 'PostController');
 resource 的方法就是讓在這個地方底下,添加對於PostController 的CRUD 等功能。
(這裡我就姑且不寫驗證了……)
  • 新增

呈現頁面為create function ;真正寫入資料庫的邏輯為store function

$post=Post::create($request->all());
return redirect('post'); 

  • 查詢

return view('show')->withPost(Post::find($id));

  • 修改

呈現頁面的為edit function ;真正更新的邏輯為update function

$post=Post::find($id);
$post->update($request->all());
return redirect('post');

  • 刪除

在destroy function 中

$post=Post::find($id);
$post->delete();
return redirect('post');

另外在頁面實作中,請在resource/view 資料夾當中新增 以.blade.php 為附檔名的檔案,注意REST_Ful URL 的規則。在form 裡面要記得呼叫 method_field(‘/接PUT 或者 Delete/’) 以及 csrf_field(),這裡我就真的不繼續詳述了,因為都是HTML 和CSS 以及Blade 的用法

總結

好吧! 我個人其實覺得我寫得很不像一個教學文章….我自己以後會好好學習寫一個教學文章的,只是對Laravel 的一個學習及筆記吧(可能只有我看得懂哈哈XDDDD)

這裡是原始碼,請大家服用!

Laravel 的世界很廣,真的有好多好多需要學習的喔,最後還是要詳看文件 看文件 看文件  很重要所以說三遍

小君曰:Laravel也有一個很不錯的CMS 教做 October-CMS 超酷的!!! 或許改天我就跳坑了吧XD