Last active
August 29, 2015 14:07
-
-
Save gbanis/4729d626c53ce20256c3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
=begin | |
LEVEL 1: DEEP IN THE CRUD | |
==================================================================== | |
CRUD = Create, Read, Update, Delete | |
CREATE | |
--------------------------------------------------------- | |
syntax: Recipe: | |
--------- --------- | |
t = tweet.new t = TableName.new | |
t.status = "I <3 brains." t.key = value | |
t.save t.save | |
Alt syntax: Recipe: | |
--------- --------- | |
t = Tweet.new( t = TableName.new(hash) | |
status: "I <3 brains", t.save | |
zombie: "Jim") | |
t.save | |
Alt syntax: Recipe: | |
--------- --------- | |
Tweet.create(status: "I <3 brains",zombie: "Jim") TableName.create(hash) | |
READ | |
-------------------------------------------------------- | |
Tween.find(2,3,4,5) => returns tweets at indeces 2,3,4,5 | |
Tweet.first => returns first tweet | |
Tweet.last => returns last tweet | |
Tweet.all => returns all tweets | |
Tweet.count => returns total number of tweets | |
Tweet.order => returns tweets, ordered by zombies | |
Tweet.limit(10) => returns the first 10 tweets | |
Tweet.where(zombie: "ash") => returns all tweets from zombie named 'ash' | |
Many of these methods can be chained together to create a complex query | |
Tweet.where(zombie: 'ash').order(:status).limit(10) | |
=> returns | |
only tweets from zombie 'ash' | |
ordered by status | |
only the first 10 | |
UPDATE | |
------------------------------------------------------------ | |
syntax Recipe | |
---------- --------------------- | |
t = Tweet.find(2) t = TableName.find(id) | |
t.zombie = "EyeballChomper" t.key = value | |
t.save t.save | |
alt syntax Recipe | |
---------- ---------- | |
t = Tweet.find(2) t = TableName.find(id) | |
t.attributes = { t.attributes = hash | |
status: "Can I munch your eyeballs?", t.save | |
zombie: "EyeballChomper" | |
} | |
t.save | |
alt syntax Recipe | |
------------- ------------- | |
t = Tweet.find(2) t = Tweet.find(2) | |
t.update( t = TableName.update(hash) | |
status: "Can I munch your eyeballs?", | |
zombie: "EyeballChomper" | |
) | |
DELETE | |
------------------------------------------------------------------ | |
syntax recipe | |
--------- --------- | |
t = Tweet.find(2) t = Table.find(id) | |
t.destroy t.destroy | |
alt syntax | |
----------- | |
t = Tweet.find(2).destroy TableName.find(id).destroy | |
alt syntax | |
----------- | |
Tweet.destroy_all TableName.destroy_all | |
=> destroys all the tweets | |
=end | |
# ===================================================================== | |
# ///////////////////////////////////////////////////////////////////// | |
# ===================================================================== | |
=begin | |
LEVEL 2: MODELS- LIFEBLOOD OF YOUR APPLICATION | |
==================================================================== | |
Models are how you communicate with your data storage in rails | |
Application stack: | |
Models | |
app/models/tweet.rb: | |
class Tweet < ActiveRecord::Base | |
end | |
t = Tweet.find(3) | |
t is an instance variable of the class | |
if we wanted to make sure that status was never blank, we | |
go back into our class and validate :status | |
class Tweet < ActiveRecord::Base | |
validates_presence_of :status | |
end | |
>> t = Tweet.new | |
=> #<Tweet id: nil, status: nil, zombie: nil> | |
>> t.save | |
=> false | |
>> t.errors.messages | |
=> {status: ["can't be blank"]} | |
>> t.errors[:status][0] | |
Rails comes with a slew of validation methods out of the box: | |
---------------------------------------------------------------- | |
validates_presence_of :status | |
validates_numericality_of :fingers | |
validates_uniqueness_of :toothmarks | |
validates_confirmation_of :password | |
validates_acceptance_of :zombiefication | |
validates_length_of :password, minimum: 3 | |
validates_format_of :email, with: /regex/i | |
validates_inclusion_of :age, in: 21..99 | |
validates_exclusion_of :age, in: 0..21, message: "sorry, you must be over 21" | |
syntax | |
--------------- | |
validates :status, presence: true | |
validates :status, length: {minimum: 3} | |
alt syntax | |
---------------- | |
validates :status, | |
presence: true, | |
length: { minimum: 3 } | |
syntax for additional options: | |
-------------------------------- | |
presence: true, | |
uniqueness: true | |
numericality: true | |
length: { minimum: 0, maximum: 2000 } | |
format: { with: /.*/ } | |
acceptance: true | |
confirmation: true | |
RELATIONSHIPS: | |
---------------------------------------- | |
Relationships exist between different tables, we need | |
a way to tell our application how to make relationships | |
"A zombie has this many tweets" | |
class Zombie < ActiveRecord::Base | |
has_many :tweets #=> lowercase, plural of the table you are referencing | |
end | |
"A tweet belongs to:" | |
class Tweet < ActiveRecord::Base | |
belongs_to :zombie #=> singular, because a tweet can only belong to 1 zombie | |
end | |
ash = Zombie.find(1) | |
=> #<Zombie id: 1, name: "Ash", graveyard: "Glen Haven Memorial Cemetary"> | |
t = Tweet.create( | |
status: "Your eyelids taste like bacon.", | |
zombie: ash | |
) | |
=> #<Tweet id: 5, status: "Your eyebalss taste like bacon.", zombie_id: 1> | |
ash.tweets.count | |
=> 3 | |
ash.tweets | |
=> [array of 3 instances that belong to ash] | |
if we fetched this tweet | |
------------------ | |
t = Tweet.find(5) | |
=> #<Tweet id: 5, status: "Your eyelids taste like bacon.", zombie_id: 1> | |
then we could call: | |
------------------ | |
t.zombie | |
=> #<Zombie id: 1, name: "Ash", graveyard: "Glen Haven Memorial Cemetary"> (instance of the zombie) | |
we could even call | |
------------------ | |
t.zombie.name | |
=> "Ash" | |
=end | |
# ===================================================================== | |
# ///////////////////////////////////////////////////////////////////// | |
# ===================================================================== | |
=begin | |
LEVEL 3: THE VIEWS AIN'T ALWAYS PRETTY | |
======================================================================= | |
Views are where we find our user interface. Views are the front end. The visual representation of our app. | |
Assuming the folder structure of our application looks like the following: | |
Zombie_twitter | |
app | |
views | |
zombies | |
tweets | |
index.html.erb (list all tweets) | |
show.html.erb (view a tweet) | |
.erb: Embedded Ruby | |
show.html.erb: | |
<!DOCTYPE html> | |
<html> | |
<head></head> | |
<body> | |
<header>...</header> | |
<!-- <% yield %> yield says "this is where the contents of this particular page goes--> | |
<!-- the following lines get moved into an external file --> | |
<% tweet = Tweet.find(1) %> | |
<h1><%= tweet.status %></h1> | |
<p><%= tweet.zombie.name %></p> | |
</body> | |
</html> | |
The above code is moist. We need to keep our code DRY: Don't repeat yourself | |
We can take this embedded code and move it out into /app/views/layouts/application.html.erb | |
syntax Creating a link inside .erb file: | |
----------------------------------------- | |
<%= link_to tweet.zombie.name, zombie_path(tweet.zombie) %> | |
should never have to hard code urls, rails comes baked in with helper functions. | |
alt syntax | |
----------------- | |
<%= link_to tweet.zombie.name, tweet.zombie %> | |
Link Recipe: | |
------------------- | |
<%= link_to text_to_show, model_instance %> | |
Looking up Documentation: | |
--------------------------------------- | |
1. Rails sourcecode | |
2. Documentation that's already been generated | |
api.rubyonrails.org | |
To use the confirm data attribute: | |
<%= link_to tweet.zombie.name, | |
tweet.zombie, | |
confirm: "Are you sure?" %> | |
Inside /app/views/tweets/index.html.erb | |
-------------------------------------------------------------------------- | |
<h1>Listing Tweets</h1> | |
<table> | |
<tr> | |
<th>Status</th> | |
<th>Zombie</th> | |
</tr> | |
<% Tweet.all.each do |tweet| %> | |
<tr> | |
<td><%= tweet.status %></td> | |
<td><%= tweet.zombie.name %></td> | |
</tr> | |
<% end %> | |
</table> | |
Tweet class | |
Tweet.all array of tweets | |
tweet single tweet | |
To create links | |
---------------------------------------------------------------------- | |
<h1>Listing Tweets</h1> | |
<table> | |
<tr> | |
<th>Status</th> | |
<th>Zombie</th> | |
</tr> | |
<% Tweet.all.each do |tweet| %> | |
<tr> | |
<td><%= link_to tweet.status, tweet %></td> | |
<td><%= link_to tweet.zombie.name, tweet.zombie %></td> | |
</tr> | |
<% end %> | |
</table> | |
What if we don't have any tweets yet? | |
------------------------------------------------------------------------------- | |
<% Tweet.all.each do |tweet| %> | |
<tr> | |
<td><%= link_to tweet.status, tweet %></td> | |
<td><%= link_to tweet.zombie.name, tweet.zombie %></td> | |
</tr> | |
<% end %> | |
---------------turns into:------------------ | |
<% tweets = Tweet.all %> # => we assign the tweets into a variable. | |
<% tweets.each do |tweet| %> # => then we loop through that variable | |
<tr> | |
<td><%= link_to tweet.status, tweet %></td> | |
<td><%= link_to tweet.zombie.name, tweet.zombie %></td> | |
</tr> | |
<% end %> | |
<% if tweets.size == 0 %> # => conditional, if tweets don't exist, print out the message | |
<em>No Tweets Found</em> | |
<% end %> | |
Edit and Delete Links | |
-------------------------------------------------------------------------------- | |
<% tweets.each do |tweet| %> # => then we loop through that variable | |
<tr> | |
<td><%= link_to tweet.status, tweet %></td> | |
<td><%= link_to tweet.zombie.name, tweet.zombie %></td> | |
<td><%= link_to "Edit", edit_tweet_path(tweet) %></td> | |
<td><%= link_to "Destroy", tweet, method: :delete %></td> | |
</tr> | |
<% end %> | |
URL Generators | |
------------------------------------------------------------ | |
Action Code The URL Notes | |
-------------------------------------------------------------------------------------------- | |
list all tweets tweets_path /tweets | |
new tweet form new_tweet_path /tweets/new | |
-------------tweet = Tweet.find(1) *****need a path for these*****------------------------------ | |
Show a tweet tweet /tweets/1 | |
Edit a tweet (tweet) /tweets/1/edit | |
Delete a tweet tweet, method: :delete /tweets/1 | |
Link Recipe: | |
--------------- | |
<%= link_to text_to_show, code %> | |
=end | |
# ===================================================================== | |
# ///////////////////////////////////////////////////////////////////// | |
# ===================================================================== | |
=begin | |
LEVEL 4: controllers | |
======================================================================= | |
Controllers: the brains of the application | |
Typically where you use models to get data out of the database, and | |
you use views to display the data that comes out of the models. | |
Application Stack: | |
Views | |
Models | |
Controllers | |
Really shouldn't be called the model in the views. Before a request goes to our model, the request | |
will go to a controller first. | |
=end | |
# Show a tweet | |
# —————————————————————————————————————————————————— | |
# /app/controllers/tweets_controller.rb | |
# -------------------------------------------- | |
class TweetsController < ApplicationController | |
def show | |
@tweet = Tweet.find(1) | |
end | |
end | |
# /app/views/tweets/show.html.erb | |
# -------------------------------------------- | |
<h1><%= @tweet.status %></h1> | |
<p>Posted by <%= @tweet.zombie.name %></p> | |
# Notes | |
# ---------------------------- | |
=begin | |
no coincidence that the show method is named the same as the view. | |
this is typically where we call our models. Let's fix it! | |
What about variable scope? We need to add the "@" symbol in front of the instance variables. | |
Grant views access to variables with "@" | |
=end | |
# Rendering a Different View | |
# ——————————————————————————————————————————————————— | |
# /app/controllers/tweets_controller.rb: | |
# ---------------------------------------- | |
class TweetsController < ApplicationController | |
def show | |
@tweet = Tweet.find(1) | |
render action: 'status' | |
end | |
end | |
# /app/views/tweets/status.html.erb | |
# --------------------------------- | |
<h1><%= @tweet.status %></h1> | |
<p>Posted by <%= @tweet.zombie.name %></p> | |
# Accepting Parameters | |
# —————————————————————————————————————————————————— | |
class TweetsController < ApplicationController | |
def show | |
@tweet = Tweet.find(params[:id]) | |
render action: 'status' | |
end | |
end | |
# if we wanted to go to different urls and specify the id of the tweets? | |
# Rails generates a hash of paramters when we use the link_to | |
# Params Recipe: | |
# --------------- | |
params = { id: "1" } | |
# Parameters | |
# —————————————————————————————————————————————————— | |
# /tweets?status=Imdead | |
params = { status: "I'm dead" } | |
@tweet = Tweet.create(status:params[:status]) | |
# /tweets?tweet[status]=Imdead | |
params = { tweet: {status: "I'm dead"} } #hash within a hash | |
@tweet = Tweet.create(status: params[:tweet][:status]) | |
# alt syntax | |
# ------------ | |
@tweet = Tweet.create(params[:tweet]) | |
# There's something rotten about this code. In Rails 4 we're required to use strong parameters. | |
# We need to specify the parameter key we require | |
require(:tweet) | |
# We also need to specify the attributes we will permit to be set. | |
permit(:status) | |
# ************** | |
@tweet = Tweet.create(params.require[:tweet].permit(:status)) | |
# ************** | |
# if there were multiple things we needed to permit, we pass in an array, like so: | |
params.require(:tweet).permit([:status, :location]) | |
@tweet = Tweet.create(params[:tweet]) | |
# Strong params required only when: | |
# Creating or Updating with Multiple Attributes | |
# Respond with XML or JSON | |
# —————————————————————————————————————————————————— | |
# Rails is great for a backend API | |
# for JSON representation of our tweet: | |
# ------------------------------------- | |
# /tweets/1.json | |
# /app/controllers/tweets_controller.rb | |
# -------------------------------------- | |
class TweetsController < ApplicationController | |
def show | |
@tweet = Tweet.find(params[:id]) | |
respond_to do |format| | |
format.html #show.html.erb | |
format.json { render json: @tweet } | |
end | |
end | |
# JSON | |
# -------- | |
{tweet: | |
{ | |
"id" : 1, | |
"status": "Where can I get a good bite to eat?", | |
"zombie_id": 1 | |
} | |
} | |
# for XML Representation of our tweet: | |
# -------------------------------------- | |
# /tweets/1.xml | |
# /app/controllers/tweets_controller.rb | |
# -------------------------------------- | |
class TweetsController < ApplicationController | |
def show | |
@tweet = Tweet.find(params[:id]) | |
respond_to do |format| | |
format.html #show.html.erb | |
format.json { render json: @tweet } | |
format.xml { render xml: @tweet } | |
end | |
end | |
# xml: | |
<?xml version="1.0" encoding="UTF-8">.... | |
# Controller Actions | |
# —————————————————————————————————————————————————— | |
class TweetsController < ApplicationController | |
def index List all tweets | |
def show Show a single tweet | |
def new show a new tweet form | |
def edit Show an edit tweet form | |
def create show an edit tweet form | |
def update update a tweet | |
def destroy delete a tweet | |
end | |
# Most of the actions will have views associated with them. | |
# Adding Some Authentication | |
# —————————————————————————————————————————————————— | |
# We need to add some sort of simple authentication. | |
# /app/controllers/tweets_controller.rb | |
# ----------------- | |
class TweetsController < ApplicationController | |
def edit | |
@tweet = Tweet.find(params[:id]) | |
if session[:zombie_id] != @tweet.zombie_id | |
flash[:notice] = "Sorry, you can't edit this tweet" | |
redirect_to(tweets_path) | |
end | |
end | |
end | |
# session: Works like a per user hash | |
# flash[:notice]: To send messages to the user | |
# redirect_to(params): allows you to redirect the browser | |
# alt syntax | |
# ---------- | |
redirect_to(tweets_path, | |
notice: "Sorry, you can't edit this tweet") | |
# Notice for layouts | |
# ------------------ | |
<html>... | |
<body>... | |
<% if flash[:notice] %> | |
<div id="notice"><%= flash[:notice] %></div> | |
<% end %> | |
<%= yield %> | |
# /app/controllers/tweets_controller.rb | |
# ------------------------------------- | |
class TweetsController < ApplicationController | |
before_action :get_tweet, only: [:edit, :update, :destroy] | |
before_action :check_auth, :only => [:edit, :update, :destroy] | |
def get_tweet | |
@tweet = Tweet.find(params[:id]) | |
end | |
def check_auth | |
if session[:zombie_id] != @tweet.zombie_id | |
flash[:notice] = "Sorry, you can't edit this tweet" | |
redirect_to(tweets_path) | |
end | |
end | |
def edit | |
def update | |
def destroy | |
end | |
# | |
# | |
# | |
# | |
# ===================================================================== | |
# ///////////////////////////////////////////////////////////////////// | |
# ===================================================================== | |
# | |
# | |
# | |
# | |
# | |
=begin | |
LEVEL 5: Routes | |
======================================================================= | |
Application Stack: | |
Views | |
Models | |
Controllers | |
Routes | |
Routing through Rails: In order to properly find these paths, and route them into actions, we need to define routes inside our router. | |
We need to define routes. | |
Inside: | |
zombie_twitter | |
config | |
routes.rb | |
=end | |
# routes.rb | |
ZombieTwitter::Application.routes.draw.do | |
resources :tweets #restful route | |
end | |
=begin | |
to create a custom route inside our router, we have to specify what method to accept | |
=end | |
ZombieTwitter::Application.routes.draw.do | |
resources :tweets #restful route | |
get '/new_tweet' => 'tweets#new' | |
# path controller#action | |
end | |
=begin Named Routes | |
=end | |
ZombieTwitter::Application.routes.draw.do | |
resources :tweets #restful route | |
get '/new_tweet' => 'tweets#new' | |
get '/all' => 'tweets#index' | |
end | |
# what if we want to link to this custom path? | |
# <%= link_to "All Tweets", "" %> | |
ZombieTwitter::Application.routes.draw.do | |
resources :tweets #restful route | |
get '/new_tweet' => 'tweets#new' | |
get '/all' => 'tweets#index', as: 'all_tweets' | |
end | |
# <%= link_to "All Tweets", all_tweets_path %> | |
# Redirect /all to /tweets | |
get '/all' => redirect('/tweets') | |
# Root Route | |
# the root domain of your site/application | |
root to: "tweets#index" | |
# Linking to root | |
# <%= link_to "All Tweets", root_path %> | |
# Route parameters | |
# what is someone wanted to enter in a zip code and only see tweets in their local area? | |
# We already have a tweets controller: | |
# /app/controllers/tweets_controller.rb | |
def index | |
if params[:zipcode] | |
@tweets = Tweet.where(zipcode: params[:zipcode]) | |
else | |
@tweets = Tweet.all | |
end | |
respond_to do |format| | |
format.html #index.html.erb | |
format.xml { render xml: @tweets } | |
end | |
end | |
# Inside our routing file: | |
get '/local_tweets/:zipcode' => 'tweets#index' | |
get '/local_tweets/:zipcode' => 'tweets#index', as: 'local_tweets' | |
# then to link to the local tweets path: | |
# <%= link_to "Tweets in 32828", local_tweets_path(32828) %> | |
# Route Parameters: | |
=begin | |
to get tweets from different users ie: | |
/eallam | |
/envylabs | |
/greggpollack | |
/github | |
etc. | |
=end | |
get ':name' => 'tweets#index', as: 'zombie_tweets' | |
# then in .erb: | |
# <%= link_to "Gregg", zombie_tweets_path('greggpollack') %> | |
# Since we're calling the index action, we need to go into that controller | |
# /app/controllers/tweets_controller.rb | |
def index | |
if params[:name] | |
@zombie = Zombie.where(name: params[:name]).first | |
@tweets = @zombie.tweets | |
else | |
@tweets = Tweet.all | |
end | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment