Skip to content

Commit

Permalink
Merge pull request Terrastories#138 from rubyforgood/csv_import
Browse files Browse the repository at this point in the history
CSV Import
  • Loading branch information
Kalimar Maia authored Oct 3, 2018
2 parents 55e1a41 + e12726f commit 9fa6ac7
Show file tree
Hide file tree
Showing 9 changed files with 253 additions and 4 deletions.
13 changes: 13 additions & 0 deletions rails/app/controllers/places_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,19 @@ def destroy
end
end


def import_csv
if params[:file].nil?
redirect_back(fallback_location: root_path)
flash[:error] = "No file was attached!"
else
filepath = params[:file].read
Place.import_csv(filepath)
flash[:notice] = "Points were imported successfully!"
redirect_back(fallback_location: root_path)
end
end

private
# Use callbacks to share common setup or constraints between actions.
def set_place
Expand Down
12 changes: 12 additions & 0 deletions rails/app/controllers/speakers_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@ def update
redirect_to speaker_path(@speaker)
end

def import_csv
if params[:file].nil?
redirect_back(fallback_location: root_path)
flash[:error] = "No file was attached!"
else
filepath = params[:file].read
Speaker.import_csv(filepath)
flash[:notice] = "Speakers were imported successfully!"
redirect_back(fallback_location: root_path)
end
end

private

def speaker_params
Expand Down
12 changes: 12 additions & 0 deletions rails/app/controllers/stories_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ def update
redirect_to story_path(@story)
end

def import_csv
if params[:file].nil?
redirect_back(fallback_location: root_path)
flash[:error] = "No file was attached!"
else
filepath = params[:file].read
Story.import_csv(filepath)
flash[:notice] = "Stories were imported successfully!"
redirect_back(fallback_location: root_path)
end
end

private

def story_params
Expand Down
11 changes: 10 additions & 1 deletion rails/app/models/place.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
class Place < ApplicationRecord
has_many :points
require 'csv'
has_many :points

def self.import_csv(filename)
CSV.parse(filename, headers: true) do |row|
loc = Place.where(name: row[0], type_of_place: row[1]).first_or_create
loc.points.create(title:row[0], lat: row[5].to_f, lng: row[4].to_f, region: row[3] )
end
end

end
7 changes: 7 additions & 0 deletions rails/app/models/speaker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,11 @@ def picture_url
ActionController::Base.helpers.image_path('speaker.png', only_path: true)
end
end

def self.import_csv(filename)
CSV.parse(filename, headers: true) do |row|
Speaker.where(name: row[0], community: row[2]).first_or_create
end
end

end
9 changes: 9 additions & 0 deletions rails/app/models/story.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,14 @@ class Story < ApplicationRecord

acts_as_taggable

def self.import_csv(filename)
CSV.parse(filename, headers: true) do |row|
pointid = Point.where(title: row[3])&.first&.id
speakerid = Speaker.where(name: row[2])&.first&.id
perm = row[9].blank? ? "anonymous" : "user_only"
Story.create(title:row[0], point_id: pointid, speaker_id: speakerid, permission_level: perm)
end
end

enum permission_level: [:anonymous, :user_only, :editor_only]
end
95 changes: 95 additions & 0 deletions rails/app/views/admin/application/_collection.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<%#
# Collection
This partial is used on the `index` and `show` pages
to display a collection of resources in an HTML table.
## Local variables:
- `collection_presenter`:
An instance of [Administrate::Page::Collection][1].
The table presenter uses `ResourceDashboard::COLLECTION_ATTRIBUTES` to determine
the columns displayed in the table
- `resources`:
An ActiveModel::Relation collection of resources to be displayed in the table.
By default, the number of resources is limited by pagination
or by a hard limit to prevent excessive page load times
[1]: https://www.rubydoc.info/gems/administrate/Administrate/Page/Collection
%>

<table aria-labelledby="<%= table_title %>">
<thead>
<tr>
<% collection_presenter.attribute_types.each do |attr_name, attr_type| %>
<th class="cell-label
cell-label--<%= attr_type.html_class %>
cell-label--<%= collection_presenter.ordered_html_class(attr_name) %>"
scope="col"
role="columnheader"
aria-sort="<%= sort_order(collection_presenter.ordered_html_class(attr_name)) %>">
<%= link_to(sanitized_order_params(page, collection_field_name).merge(
collection_presenter.order_params_for(attr_name, key: collection_field_name)
)) do %>
<%= t(
"helpers.label.#{collection_presenter.resource_name}.#{attr_name}",
default: attr_name.to_s,
).titleize %>
<% if collection_presenter.ordered_by?(attr_name) %>
<span class="cell-label__sort-indicator cell-label__sort-indicator--<%= collection_presenter.ordered_html_class(attr_name) %>">
<svg aria-hidden="true">
<use xlink:href="#icon-up-caret" />
</svg>
</span>
<% end %>
<% end %>
</th>
<% end %>
<% [valid_action?(:edit, collection_presenter.resource_name),
valid_action?(:destroy, collection_presenter.resource_name)].count(true).times do %>
<th scope="col"></th>
<% end %>
</tr>
</thead>

<tbody>
<% resources.each do |resource| %>
<tr class="js-table-row"
tabindex="0"
<% if valid_action? :show, collection_presenter.resource_name %>
<%= %(role=link data-url=#{polymorphic_path([namespace, resource])}) %>
<% end %>
>
<% collection_presenter.attributes_for(resource).each do |attribute| %>
<td class="cell-data cell-data--<%= attribute.html_class %>">
<% if show_action? :show, resource -%>
<a href="<%= polymorphic_path([namespace, resource]) -%>"
class="action-show"
>
<%= render_field attribute %>
</a>
<% end -%>
</td>
<% end %>
<% if valid_action? :edit, collection_presenter.resource_name %>
<td><%= link_to(
t("administrate.actions.edit"),
[:edit, namespace, resource],
class: "action-edit",
) if show_action? :edit, resource%></td>
<% end %>
<% if valid_action? :destroy, collection_presenter.resource_name %>
<td><%= link_to(
t("administrate.actions.destroy"),
[namespace, resource],
class: "text-color-red",
method: :delete,
data: { confirm: t("administrate.actions.confirm") }
) if show_action? :destroy, resource %></td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
80 changes: 80 additions & 0 deletions rails/app/views/admin/application/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<%#
# Index
This view is the template for the index page.
It is responsible for rendering the search bar, header and pagination.
It renders the `_table` partial to display details about the resources.
## Local variables:
- `page`:
An instance of [Administrate::Page::Collection][1].
Contains helper methods to help display a table,
and knows which attributes should be displayed in the resource's table.
- `resources`:
An instance of `ActiveRecord::Relation` containing the resources
that match the user's search criteria.
By default, these resources are passed to the table partial to be displayed.
- `search_term`:
A string containing the term the user has searched for, if any.
- `show_search_bar`:
A boolean that determines if the search bar should be shown.
[1]: https://www.rubydoc.info/gems/administrate/Administrate/Page/Collection
%>
<% content_for(:title) do %>
<%= display_resource_name(page.resource_name) %>
<% end %>

<header class="main-content__header" role="banner">
<h1 class="main-content__page-title" id="page-title">
<%= content_for(:title) %>
</h1>

<% if show_search_bar %>
<%= render(
"search",
search_term: search_term,
resource_name: display_resource_name(page.resource_name)
) %>
<% end %>

<div>
<%= link_to(
t(
"administrate.actions.new_resource",
name: page.resource_name.titleize.downcase
),
[:new, namespace, page.resource_path],
class: "button",
) if valid_action?(:new) && show_action?(:new, new_resource) %>
</div>
</header>

<section class="main-content__body main-content__body--flush">
<%= render(
"collection",
collection_presenter: page,
collection_field_name: resource_name,
page: page,
resources: resources,
table_title: "page-title"
) %>
<%= paginate resources %>
</section>

<% if ["place", "story", "speaker"].include?(page.resource_name) %>
<%= form_tag send("import_csv_#{page.resource_name.pluralize}_path"), multipart: true do %>
<div class="form-group">
<label for="file">File to Upload</label><%= file_field_tag :file, :accept => 'text/csv', class: "form-control-file" %>
</div>
<br>
<div class="form-group">
<%= button_tag :class => "btn btn-lg btn-primary" do %>
<i class="fa fa-upload"></i> Import <%= page.resource_name.pluralize.capitalize %>
<% end %>
</div>
<% end %>
<% end %>
18 changes: 15 additions & 3 deletions rails/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,25 @@
end

scope "(:locale)", locale: /en|mat/ do
resources :places
resources :stories
resources :places do
collection do
post :import_csv
end
end
resources :stories do
collection do
post :import_csv
end
end
devise_for :users, :controllers => { registrations: 'registrations' }
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
root to: 'welcome#index'
get 'home', to: 'home#index', as: "home_map"
resources :points
resources :speakers
resources :speakers do
collection do
post :import_csv
end
end
end
end

0 comments on commit 9fa6ac7

Please sign in to comment.