Overview
- Same thing but with different vocab
- Gain perspective by looking at the differences
- Examining them out of the box
├── urls.py
│ ├── jobs
│ │ ├── models.py
│ │ ├── views.py
│ │ ├── forms.py
│ │ └── urls.py
│ ├── applicatants
│ │ ├── models.py
│ │ ├── views.py
│ │ ├── forms.py
│ │ └── urls.py
│ ├── templates
│ │ ├── index.html
│ │ └── create_jobs.html
├── app
│ ├── controllers
│ │ ├── application_controller.rb
│ │ ├── concerns
│ │ └── jobs_controller.rb
│ ├── helpers
│ │ └── application_helper.rb
│ ├── models
│ │ ├── concerns
│ │ └── job.rb
│ └── views
│ ├── jobs
│ │ ├── edit.html.erb
│ │ ├── _form.html.erb
│ │ ├── index.html.erb
│ │ ├── new.html.erb
│ │ └── show.html.erb
│ ├── layouts
│ │ └── application.html.erb
Reflections
- Rails is simpler
- Django has smaller conceptal units
- Django solves the lib problem
- Django can have giant models files
<form action="/jobs" method="post">
<label for="job_name">Name</label>
<input type="text" name="job[name]" id="job_name" />
<label for="job_description">Description</label>
<textarea name="job[description]" id="job_description">
<input type="submit" value="Create Job" class="button" />
</form>
app/views/jobs/_form.html.erb
<%= form_for(@job) do |f| %>
<%= f.error_notification %>
<%= f.text_field :name %>
<%= f.text_area :description %>
<%= f.text_field :company_name %>
<%= f.text_field :url %>
<%= f.date_field :start_date %>
<%= f.submit %>
<% end %>
Reflections
- Rails is easier for a designer to change
- Django autodiscovers sensible form widgets
- Django hides FE logic deep within the backend
urls.py
from django.conf.urls import include, patterns
urlpatterns = patterns(
'',
(r'^jobs/', include("skill_and_love.job.urls")),
)
job/urls.py
from django.conf.urls import url, patterns
from .views import CreateJobView
urlpatterns = patterns(
'',
url(r'^create/$', CreateJobView.as_view(), name='job_create'),
)
config/routes.rb
Rails.application.routes.draw do
resources :jobs, only: :create
end
Reflections
- Django is explicit
- Django is unopinionated about app structure
- Rails is RESTful
job/views.py
from django.views.generic import CreateView
from .models import Job
from .forms import CreateJobForm
class JobCreateView(CreateView):
model = Job
form_class = CreateJobForm
CreateView
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
app/controllers/jobs_controller.rb
class JobsController < ApplicationController
def create
@job = Job.new(job_params)
if @job.save
redirect_to @job, notice: 'Job was successfully created.'
else
render :new
end
end
end
Reflections
- Django's views encapsulate common patterns
- Django's views encourage code sharing
- Django uses the template pattern
- The template pattern can be confusing
- Rails controllers are very imperative
job/models.py
from django.db import models
class Job(models.Model):
name = models.CharField(max_length=100, null=False)
published = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
$ python manage.py makemigrations jobs
$ bin/rails generate migration CreateJobs
db/migrate/20150223155659_create_jobs.rb
class CreateJobs < ActiveRecord::Migration
def change
create_table :jobs do |t|
t.text :name, null: false
t.boolean :published, null: false
t.timestamps null: false
end
end
end
db/schema.rb
create_table "jobs", force: :cascade do |t|
t.text "name", null: false
t.boolean "published", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Reflections
- Rails' schema is centralized
- Django's migrations are an imperfect solution to migration conflicts
job/models.py
from django.db import models
from .managers import JobsManager
class Job(models.Model):
objects = JobsManager()
job/managers.py
from django.db.models import Manager
class JobManager(Manager):
def published(self):
return self.filter(published=True)
>>> Job.objects.get(id=2)
>>> Job.objects.all()
>>> Job.objects.published()
app/models/job.rb
class Job < ActiveRecord::Base
scope :published { where(published: true) }
end
>>> Job.find(2)
>>> Job.all
>>> Job.published
Reflections
- Rail's scopes clutter the model
- Django's Managers allow the models to have a cleaner API
Philosophical Differences
Django's Upsides
- Coding Standards
- Culture of Documentation
- Explicit Imports
Rail's Upsides
- Logging
- Packaging
- Functional Programming Support
- Readablity
@rmeritz
rebecca.meritz.com/pycon-sweden-2015
May 12-13, 2015