Skip to content
This repository has been archived by the owner on Jun 20, 2018. It is now read-only.

Filters on junior story model #16

Merged
merged 22 commits into from
Dec 11, 2016
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
ef6471a
adds swap files to gitignore
TPei Mar 6, 2016
d755bc3
adds Filterable model to junior_stories_controller, allows for url fi…
TPei Mar 6, 2016
fce0c7a
merge master
TPei Mar 6, 2016
ea3ee19
can_publish does not exist anymore, apparently^^
TPei Mar 6, 2016
27c156b
needs to exclude format param as well
TPei Mar 6, 2016
5db541b
adds tests for paramter filtering
TPei Mar 7, 2016
daadee6
adds error handling to Filterable, adds specs for illegal filter params
TPei Mar 7, 2016
55d087d
updates strings to use single quotes
TPei Mar 7, 2016
5f37082
spec for a combination of legal and illegal filter params
TPei Mar 7, 2016
16fbfe1
adds filter modal with all fields listed to search through
TPei Mar 7, 2016
7541125
ommits a couple fields from filter list
TPei Mar 7, 2016
429689a
like this layout better
TPei Mar 7, 2016
6a6534f
ids should also not be filterable
TPei Mar 7, 2016
8e51c28
instead of loading attributes from model, I provide a hash with demo …
TPei Mar 7, 2016
022b352
form now points to actual action, submits fields, filtering works :)
TPei Mar 7, 2016
af43203
maked download as csv work with filtered stories
TPei Mar 7, 2016
7a55b10
maked allowed_params more centralized and clean
TPei Mar 7, 2016
a94752c
revert unwanted vim indentation change
TPei Mar 7, 2016
ff6ba83
split params into allowed and required to remove duplication
TPei Mar 13, 2016
0220014
hides filter reset button if nothing was filtered
TPei Mar 13, 2016
e9e4dbe
fix filename
TPei Dec 9, 2016
84979cc
Merge branch 'master' into filters_on_junior_story_model
TPei Dec 10, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@
/log/*
!/log/.keep
/tmp
*.swp
45 changes: 43 additions & 2 deletions app/controllers/junior_stories_controller.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
class JuniorStoriesController < ApplicationController

def index
@junior_stories = JuniorStory.all
@junior_stories = JuniorStory.
filter(allowed_params)

@fields = fields
@csv_params = allowed_params.merge({ format: 'csv' })

respond_to do |format|
format.html
format.csv { send_data @junior_stories.to_csv, type: 'application/csv' }
format.csv { send_data @junior_stories.to_csv, type: 'application/csv', filename: 'junior_stories.csv' }
end
end

Expand Down Expand Up @@ -33,4 +37,41 @@ def junior_story_params
:remote, :tech_team_size, :company_size, :company_age, :person_of_colour, :other,
:publishing_consent, :freelancer)
end

def allowed_params
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these values are exactly the same as the junior_story_params above, aren't they - what's the benefit of doing it this way?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, the difference is in the require(:junior_story). Do we really need that above?

params.permit(:job, :happy_in_job, :happy_info,
:gender, :city, :country, :days_per_week, :salary, :currency, :technology, :focus,
:age, :years_working_in_total, :years_working_at_job, :education, :first_job,
:remote, :tech_team_size, :company_size, :company_age, :person_of_colour, :other,
:publishing_consent, :freelancer)
end

# TODO: shouldn't hard code this, but I like having demo search terms in the list
def fields
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would think that this belongs in the model, not the controller. wdyt?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this really truly belongs anywhere^^ What makes you say it's better suited for the model? Thin controllers - fat models?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup :)

{
job: "junior developer",
happy_in_job: "yes",
happy_info: "It's ok",
gender: "female",
city: "Berlin",
country: "DE",
days_per_week: "5",
salary: "15000",
currency: "€",
technology: "RoR",
focus: "backend",
age: 30,
years_working_total: "less than 1 year",
years_working_at_job: "less than 1 year",
education: "self taught",
first_job: "no",
remote: "no",
tech_team_size: "5 - 10 people",
company_size: "less than 10 people",
company_age: 5,
person_of_colour: false,
other: "Thanks",
freelancer: "f"
}
end
end
15 changes: 15 additions & 0 deletions app/models/concerns/filterable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module Filterable
extend ActiveSupport::Concern

module ClassMethods
def filter(params)
results = self.all
params.each do |key, value|
if results.column_names.include? key
results = results.where(key => value) if value.present?
end
end
results
end
end
end
1 change: 1 addition & 0 deletions app/models/junior_story.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require 'csv'

class JuniorStory < ActiveRecord::Base
include Filterable

validates :salary, presence: true
validates :currency, presence: true
Expand Down
37 changes: 36 additions & 1 deletion app/views/junior_stories/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,42 @@
<h1>Junior Stories:</h1>
</div>

<%= link_to "Download as CSV", junior_stories_path(format: "csv"), class: 'btn btn-info' %>
<%= link_to "Download as CSV", junior_stories_path(@csv_params), class: 'btn btn-info' %>
<!-- Button trigger modal -->
<button type="button" class="btn btn-info" data-toggle="modal" data-target="#myModal">
Filter Stories
</button>
<%= link_to "Reset filters", junior_stories_path, class: 'btn btn-info' %>

<!-- Filter Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<%= form_tag({controller: "junior_stories", action: "index" }, { method: "get", class: "form-horizontal" }) do %>
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="myModalLabel">Filter for Fields</h4>
</div>
<div class="modal-body">
<% @fields.each do |name, demo_value| %>
<div class="form-group">
<div class="col-sm-offset-1"></div>
<label class="col-sm-4 control-label"><%= name %></label>
<div class="col-sm-6">
<input type="text" class="form-control" name="<%= name %>" placeholder="<%= demo_value %>">
</div>
</div>
<% end %>
</div>

<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Filter</button>
</div>
</div>
<% end %>
</div>
</div>

<div class='junior-stories'>
<% @junior_stories.each do |j| %>
Expand Down
82 changes: 70 additions & 12 deletions spec/controllers/junior_stroy_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,80 @@

describe JuniorStoriesController do
describe 'GET index' do
it 'assigns @junior_stories' do
story = build :junior_story
story.save
get :index
expect(assigns(:junior_stories)).to eq([story])
context 'without filter params' do
it 'assigns @junior_stories' do
story = build :junior_story
story.save
get :index
expect(assigns(:junior_stories)).to eq([story])
end

it 'renders the index template' do
get :index
expect(response).to render_template('index')
end

it 'does not render index, but instead responds with csv' do
get :index, format: 'csv'
expect(response).not_to render_template('index')
expect(response.content_type).to include 'application/csv'
end
end

it 'renders the index template' do
get :index
expect(response).to render_template('index')
context 'with legal filter params' do
it 'returns only the filter appropriate junior_story' do
female_story = build :junior_story
female_story.gender = 'female'
female_story.save

male_story = build :junior_story
male_story.gender = 'male'
male_story.save


get :index, { 'gender' => 'female' }
expect(assigns(:junior_stories)).to eq([female_story])
end

it 'renders the index template' do
get :index, { 'gender' => 'female' }
get :index
expect(response).to render_template('index')
end

it 'does not render index, but instead responds with csv' do
get :index, { 'gender' => 'female', 'format' => 'csv' }
expect(response).not_to render_template('index')
expect(response.content_type).to include 'application/csv'
end
end

it 'does not render index, but instead responds with csv' do
get :index, format: 'csv'
expect(response).not_to render_template('index')
expect(response.content_type).to include 'application/csv'
context 'with illegal filter params' do
it 'ignores illegal filter params but respects legal filter params' do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I can see, you are testing here the possibility of someone sending illegal params through the filter... is that right? Does this need testing? Isn't this handled by strong parameters anyway?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a more useful spec could be a feature spec whereby a user chooses a filter & then gets the right junior story back.

female_story = build :junior_story
female_story.gender = 'female'
female_story.save

male_story = build :junior_story
male_story.gender = 'male'
male_story.save


get :index, { 'makes_no_sense' => 'random', 'gender' => 'female' }
expect(assigns(:junior_stories)).to eq([female_story])
end

it 'renders the index template' do
get :index, { 'makes_no_sense' => 'random' }
get :index
expect(response).to render_template('index')
end

it 'does not render index, but instead responds with csv' do
get :index, { 'makes_no_sense' => 'random', 'format' => 'csv' }
expect(response).not_to render_template('index')
expect(response.content_type).to include 'application/csv'
end
end
end
end