Using will_paginate with array routing issue - ruby

My project is currently configured to only have one view, import.html, that allows the user to upload and view contents of a CSV file (after uploading).
Here is the controller class import method:
class UploadController < ApplicationController
require "CSV"
require 'will_paginate/array'
def import
return if params[:file] == nil
file = params[:file]
#table = []
rowi = 0
CSV.foreach(file.path) do |row|
if rowi == 0 #and headers (for later)
#headers = row
else
#table << row.join("~")
end
rowi = rowi + 1
end
#table = #table.paginate(page: params[:page], :per_page => 20)
session
end
end
Here is the view:
<h1>Upload#import</h1>
<h4>UPLOAD A CSV FILE:</h4>
<%= form_tag({:action => "import"}, multipart: true) do %>
<%= file_field_tag :file %>
<%= submit_tag( "Import" ) %>
<% end %>
<% if #headers and #table %>
<h1>RESULTS</h1>
<table>
<thead>
<tr>
<% #headers.each do |column| %>
<td><%= column %></td>
<% end %>
</tr>
</thead>
<tbody>
<% #table.each do |row| %>
<tr>
<% row.split("~").each do |cell| %>
<td><%= cell %></td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
<%= will_paginate #table, inner_window: 1, outer_window: 0%>
<% end %>
Here are the routes:
Rails.application.routes.draw do
root 'upload#import'
post "/" => "upload#import"
end
When interacting with my table to go to a different page, my routes have no specified instruction for:
GET "/?page=(pagenumber)"
I don't know what to tell it to do in order for the correct page to show.
It just defaults to redirecting to the import_page which clears all the data that has been imported. How should I fix this?

In a nutshell, you'll likely want to use a singular resource for this.
So you'd need the following:
In routes.rb:
resource :uploader, only: [:show, :create]
(N.B. this is a different use case to the more commonly-seen resources plural.)
This will give you the following routes:
POST /upload uploads#create # create the new upload
GET /upload uploads#show # display the one and only upload resource
In your controller:
class UploadController < ApplicationController
require "csv"
require 'will_paginate/array'
def create
return if params[:file] == nil
file = params[:file]
#table = []
rowi = 0
CSV.foreach(file.path) do |row|
if rowi == 0 #and headers (for later)
#headers = row
else
#table << row.join("~")
end
rowi = rowi + 1
end
# save the file to the db
# redirect to upload_path
end
def show
# Find the relevant table
#table = Table.last.paginate(page: params[:page], :per_page => 20)
end
end
Then you'll want to rework the form in your view to use #table, something like:
...
<%= form_for #table, multipart: true) do %>
<%= f.file_field :file %>
<%= f.submit "Import" %>
<% end %>
...
This is a very basic summary of how your project should work. The crux of it is using the correct, separate actions to create and show the table.
You'll likely want to look at using strong params and other Rails conventions.
Finally, if it helps, have a look at a generated Rails controller (i.e. rails generate controller my_example_controller) - this will have the create and show actions pre-built, and you can look to merge your code into something similar.
Hope this helps - give me a shout if you've any questions.

Related

Error trying to call a method on an object that belongs to another object

I have recs, which belong to a list, and lists, which have many recs. I am trying to figure out why I can't call my 'to_do' method below on the recs that belong to a list? This is in the 2nd row of view code. I'm getting the following error:
SQLite3::SQLException: near ")": syntax error: SELECT "recs".* FROM "recs" WHERE "recs"."list_id" = ? AND (done = 'false'))
Rec Model
class Rec < ActiveRecord::Base
belongs_to :list
scope :to_do, lambda {where("done = ?)", 'false')}
end
List model
class List < ActiveRecord::Base
has_many :recs
end
Controller
def index
#recs = Rec.to_do
#lists = List.all
#networks = Network.all
end
View
<% network.lists.eat_lists.each do |list| %>
<% if list.recs.to_do.present? %>
<%= list.name %></br>
<% list.recs.each do |rec| %>
<%= rec.name.split(',').first %>
<%= rec.notes %>
<%= rec.done %>
<%= link_to 'Done', marked_as_done_url(rec), method: :patch %></br>
<%= link_to 'Delete', rec, method: :delete %></br>
<% end %>
<% end %>
<% end %>
change your scope to this scope :to_do, lambda {where("done = ?", false)} or scope :to_do, lambda {where(done:false}, notice i have removed one closing bracket in string

How to dry code?

I am working with has many through association in Application.
I access email from employee table in INDEX action of InventoryController like below code:
<% #inventories.each do |inventory| %>
<% inventory.employee_inventories.each do |e| %>
<%if e[:status]== 'ALLOTED'%>
<%= e.employee.email%>
<% end %>
<% end %>
<% end %>
Please help me How to DRY this code in view? Thanks in advance
#alloted_emails = #inventories.flat_map(&:employee_inventories).select do |i|
i[:status] == 'ALLOTED'
end.map do |i|
i.employee.email
end
Unless you want to create a scope as suggested by #Pavan, just introduce this var and use it.
If you are using the same code in different views then you can create a helper.
Otherwise write down this code like-
<% #inventories.each do |inventory| %>
<% inventory.employee_inventories.each do |e| %>
<%= e.employee.email if e[:status]== 'ALLOTED' %>
<% end %>
<% end %>
The main problem in your code is n+1 query problem. If you are using eager loading then there is no issue otherwise use eager loading using includes keyword in your query.

passing multiple id with URL using Rails 3

my requirement is passing array of ids with URL and extract them into controller method.Suppose I have the ids like below.
#userid=[1,2,3,4]
I have the link_to tag like below.
<%= link_to "update",users_update_path(:all_id=#userid) %>
In users_controller.rb file i want to access all id which are present in #userid variable.
users_controller.rb:
class UsersController < ApplicationController
def update
end
end
Please help me to resolve this issue.
convert the array into string and pass string to controller like
<% c= #userid.join(‘,’) %>
<%= link_to "update",users_update_path(:ids => c) %>
in controller using split method convert string back to array
class UsersController < ApplicationController
def update
s = params[:ids]
#ids = s.split(/,/)
end
end
in routes.rb
match ‘your_users_update_path/:ids’ => ‘users#update’
You can try this, I hope this will help.
<%= link_to "update",users_update_path(params.merge!(:all_id => [1,2,3,4])) %>
## Output
puts params[:all_id]
[1,2,3,4]
Try this:
<%= link_to "update",users_update_path(:all_id => #userid.to_s) %>
users_controller.rb:
class UsersController < ApplicationController
def update
#user_ids = params[:all_id]
end
end

Ajax and Ruby on Rails with local variable?

I really don't get how to use Ajax with Ruby on Rails. I must be missing something simple.
What I want to do is to ask the user to select a date, and then make a table of documents appear, but only with the selected date (Date is an attribute of Document).
My idea is to create a local variable witch is not in my database, store the selected date in it, and then create a loop in my view saying for example #document.where(:date = date).each...
In app/controllers/documents_controller.rb, I have :
class DocumentsController < ApplicationController
def information
#documents = Document.all
#date = params[:date]
respond_to do |format|
format.html # index.html.erb
format.js{}
format.json { render json: #documents}
end
end
end
And in app/views/documents/_information.js.erb, I have:
<%= form_tag(document, :remote => true) do %>
<%= label_tag(:date, "The selected date is:") %>
<%= text_field_tag(:date) %>
<%= submit_tag %>
<% end %>
In the end, I have a field where the user puts his date, but the submit button doesn't do anything.
What do I miss ?
As discussed you need to change the flow of your app.Lets go through steps one by one
a. create your input field where you are selecting your date field. You already have your form for that
<%= form_tag(you_path_for_information_method, :remote => true) do %>
<%= label_tag(:date, "The selected date is:") %>
<%= text_field_tag(:date) %>
<%= label_tag(:portfolio, "Add portfolio") %>
<%= text_field_tag(:portfolio) %>
<%= submit_tag %>
<% end %>
In controller
def information
#documents = Document.all
#date = params[:date]
#portfolio = Portfolio.find(params[:portfolio])
respond_to do |format|
format.js{}
end
end
In your information.js.erb you can have:
$("#some_id_of_parent").html("<%=j render partial: "your_partial", locals: {portfolio: #portfolio} %>")

How can I use do edit-in-place on three different models from a View for a model those three belong_to?

I would like to enable edit-in-place functionality in a View that displays values from different models:
This is what I use currently and it does NOT work, but would like some alternatives:
I have a model called Campaign. In the controller, I do the following to list, in order, the three Models that belong_to a Campaign:
<% #campaign_events = campaign_events %>
<% #campaign_events.each do |campaign_event| %>
<% model_name = campaign_event.class.name.tableize.singularize %>
<p>
<%= link_to campaign_event.title, send("#{model_name}_path", campaign_event) %>
<span class='model_name'>(<%= model_name.capitalize %>)</span>
<%= campaign_event.days %> Days
</p>
<% end %>
campaign_event is a campaign_helper defined as:
module CampaignsHelper
def campaign_events
return (#campaign.calls + #campaign.emails + #campaign.letters).sort{|a,b| a.days <=> b.days}
end
end
I want to be able to click on the numerical value for Days when looking at the view/campaign/show and edit the value for :days (in this case, displayed as campaign_event.days
I'm not really sure about it, but I'll try to help... I believe something like the following may work for you:
# calls controller
in_place_edit_for :call, :days
# emails controller
in_place_edit_for :email, :days
# letters controller
in_place_edit_for :letter, :days
# campaign view
<% #campaign_events = campaign_events %>
<% #campaign_events.each do |campaign_event| %>
<% controller_name = campaign_event.class.name.tableize %>
<% model_name = controller_name.singularize %>
<p>
<%= link_to campaign_event.title,
send("#{model_name}_path", campaign_event) %>
<span class='model_name'>(<%= model_name.capitalize %>)</span>
<%= in_place_editor_field model_name, :days, {},
:url => {
:controller => controller_name,
:action => 'set_#{model_name}_title',
:id => campaign_event.id} %> Days
</p>
<% end %>
There's somethings I don't know exactly how to do:
1) in_place_editor_field model_name
I believe this won't work, but I don't know how to pass the model_name.
2) :action => 'set_#{controller_name}_title'
Not sure about it also. Just doesn't look right.
Anyway, hope it helps you... and forgive me if this is completely stupid.

Resources