How to use index action of controller of a model that belongs to another model? - ruby-on-rails-5

I'm coding a rails application to handle scheduling for university classes. Currently, I'm trying to make an index page to show all of the sections in the database, but I'm getting this error:
No route matches {:action=>"index", :controller=>"sections"}
However, when I look at my routes, I can see a controller action pair for section and index.
bin/rails routes
Prefix Verb URI Pattern Controller#Action
home_index GET /home/index(.:format) home#index
course_sections GET /courses/:course_id/sections(.:format) sections#index
POST /courses/:course_id/sections(.:format) sections#create
new_course_section GET /courses/:course_id/sections/new(.:format) sections#new
edit_course_section GET /courses/:course_id/sections/:id/edit(.:format) sections#edit
course_section GET /courses/:course_id/sections/:id(.:format) sections#show
PATCH /courses/:course_id/sections/:id(.:format) sections#update
PUT /courses/:course_id/sections/:id(.:format) sections#update
DELETE /courses/:course_id/sections/:id(.:format) sections#destroy
courses GET /courses(.:format) courses#index
POST /courses(.:format) courses#create
new_course GET /courses/new(.:format) courses#new
edit_course GET /courses/:id/edit(.:format) courses#edit
course GET /courses/:id(.:format) courses#show
PATCH /courses/:id(.:format) courses#update
PUT /courses/:id(.:format) courses#update
DELETE /courses/:id(.:format) courses#destroy
students GET /students(.:format) students#index
POST /students(.:format) students#create
new_student GET /students/new(.:format) students#new
edit_student GET /students/:id/edit(.:format) students#edit
student GET /students/:id(.:format) students#show
PATCH /students/:id(.:format) students#update
PUT /students/:id(.:format) students#update
DELETE /students/:id(.:format) students#destroy
root GET / home#index
rails_service_blob GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs#show
rails_blob_representation GET /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show
rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show
update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update
rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create
Why does it not route correctly?
My section controller looks like this:
class SectionsController < ApplicationController
def index
#courses = Course.all
end
def create
#course = Course.find(params[:course_id])
#section = #course.sections.create(section_params)
end
def update
#course = Course.find(params[:course_id])
#section = #course.sections.find(params[:id])
#section.update(section_params)
end
def destroy
#course = Course.find(params[:course_id])
#section = #course.sections.find(params[:id])
#section.destroy
end
private
def section_params
params.require(:section).permit(:section_letter, :section_professor, :section_meetings, :section_capacity)
end
end
My index.html.erb view in the sections folder looks like this:
<h2>Sections</h2>
<table>
<tr>
<th>Number</th>
<th>Section</th>
<th>Name</th>
<th>Credit Hours</th>
<th>Professor</th>
<th>Meetings</th>
<th>Capacity</th>
</tr>
<% #courses.each do |course| %>
<% course.sections.each do |section| %>
<tr>
<td><%= course.course_num %></td>
<td><%= section.section_letter %></td>
<td><%= course.course_name %></td>
<td><%= course.course_credits %></td>
<td><%= section.section_professor %></td>
<td><%= section.section_meetings %></td>
<td><%= section.section_capacity %></td>
</tr>
<% end %>
<% end %>
</table>
And my routes file looks like:
Rails.application.routes.draw do
get 'home/index'
resources :courses do
resources :sections
end
resources :students
root 'home#index'
end
Any help is appreciated!

Its because the sections controller is a nested resource under the courses resource. There is a sections#index but it takes a :course_id parameter.
In other words there is no /sections path that directly maps to sections#index
If its a one-off endpoint you can declare this route
get 'sections' => 'sections#index', as: :sections
And you'd then need to update the #index method in the SectionsController and just pull all Sections like
#sections = Section.all

Related

Getting input from view to scope an index

So I am trying to add the ability to select a user in the view, and then return only the Lists that are associated with that user. I can do this for now hard coded in the controller.
def show
#some_lists = List.sort(:boolean => true, :user_id => 3)
respond_to do |format|
format.html # show.html.erb
format.json { render json: #some_list }
end
end
But I want to be able to choose the user from the views
<% #some_lists.each do |list| %>
<tr>
<td><%= list.id_name %></td>
<td><%= list.day %></td>
<td><%= list.start_time %></td>
<td><%= list.end_time %></td>
</tr>
<% end %>
What is the best way to go about doing this, I also plan on adding the ability to sort by the list.start_time and list.end_time as well
You'll definitely want to do this with AJAX. For the specific thing you want to do (filtering/sorting a table) there's a javascript plugin I would recommend:
DataTables
(you'll want to check out the documentation on server-side processing)
There's even a really nice tutorial to using it with rails in RailsCast #340

Rails 3 export csv from partial?

I followed RBate's Railscast on the subject, but I have a caviat.
The view starts with a form to define the table's variables. On clicking submit, the form posts back to the same view and re-renders the partial (which is just the HTML table). It's not AJAX, it's all form params.
RBates uses a single variable and calls .to_csv on it. I have a complex table with many variables defined by the params and so don't know how to call .to_csv on the entire HTML table.
I need to be able to export just the results in the partial.
Thanks in advance for the ideas.
&&&&&&&& AS REQUESTED, SAMPLE CODE: &&&&&&&&
So, the full code is probably more confusing than helpful, but here's a slimmed down version:
stats/reporter.html.erb: (stat_reporter_path matches this URI)
<%= form_tag( :stat_reporter, method: :post ) do %>
form is in here
<%= submit_tag "Get my report" %>
<% end %>
<div>
<%= render 'stat_select' %>
</div>
stats/_stat_select:
<table>
<thead>
<tr>...column heads...</tr>
</thead>
<tbody>
<% #counties.each do |c| %>
<td><%= c.name %></td>
<% c.programs.each do |p| %>
<td><%= p.name %></td>
<% p.events.each do |e| %>
<td><%= e.name %></td>
...and so on...
</table>
Here's a screenshot
Looking back on this post, I would:
Create a link to a new view and pas all the variables to in the URL.
That view would use all the variables to create an HTML output that could be used to create the to_csv method
Once the csv file was created, the controller would render the original view.

Combine API data with local data in Rails

I am working with the GoCardless API in my Rails 3 application. I have a subscription model which has a resource_id column which matches the id of the remote record.
I am trying to get extra information for a local subscription record from the API.
Subscription Index View
<% #subscriptions.each do |subscription| %>
<tr>
<td><%= subscription.resource_id %></td>
<td><%= subscription.resource_type %></td>
<td><%= subscription.signature %></td>
<td><%= subscription.state %></td>
<td><%= #gocardless.next_interval_start %></td>
<td><%= link_to 'Show', subscription %></td>
<td><%= link_to 'Edit', edit_subscription_path(subscription) %></td>
<td><%= link_to 'Destroy', subscription, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
Subscription Controller
def index
#subscriptions = Subscription.all
#gocardless = GoCardless::Merchant.find("XXXXXXXXXX").subscriptions
respond_to do |format|
format.html # index.html.erb
format.json { render json: #subscriptions }
end
end
As you can see I'm using the following line to retrieve the next interval start date
<%= #gocardless.next_interval_start %>
This doesn't work and returns nil. However, if I change it to the following all records show the value from the first record from the API.
<%= #gocardless.first.next_interval_start %>
According to the GoCardless API documentation you can lookup a subscription using the following:
GoCardless::Subscription.find("XXXXXXXXXX") # => #<GoCardless::Subscription ...>
So, my question. How do I pass the current subscription resource_id to the API so that I can view the next_internal_start value for each of the local subscription records?
Update
Using Adam's example below I get a 404 response from GoCardless. I think it's due to me not setting the merchant ID in the request. When I change the method to:
def gc_subscription
#gc_subscription ||= GoCardless::Merchant.find("MERCHANTID").subscriptions.find(self.resource_id)
end
I get undefined methodinterval' for #` for any attribute I try and request using the following code:
<% for subscription in #subscriptions %>
<%= subscription.gc_subscription.amount
<% end %>
When using the same code to get local content it works as expected:
<% for subscription in #subscriptions %>
<%= subscription.resource_id %>
<% end %>
I've checked that the value I am trying to retrieve is available in the API. https://sandbox.gocardless.com/docs/api_guide#resources-available
Update Two
As before calling the first result works using Adam's method:
<%= subscription.gc_subscription.first.amount %>
This returns 2.5 which is the value of the first subscription.
If I had a local Subscription model which linked to a remote data source I would have a method like this on my Subscription model which provided access to the remote object:
def gc_subscription
#gc_subscription ||= GoCardless::Subscription.find(self.resource_id)
end
Then you can access this method as necessary without any need for any GC logic in the view or controller. For example:
for subscription in #subscriptions
subscription.gc_subscription.some_method #=> "output"
end
Or, if you are only working with one subscription:
subscription = Subscription.find(id)
subscription #=> Your local Subscription instance
subscription.gc_subscription #=> GoCardless::Subscription instance
With it configured like that, you will be able to remove the #gocardless from your controller and replace your view with this:
<% #subscriptions.each do |subscription| %>
<tr>
<td><%= subscription.resource_id %></td>
<td><%= subscription.resource_type %></td>
<td><%= subscription.signature %></td>
<td><%= subscription.state %></td>
<td><%= subscription.gc_subscription.next_interval_start %></td>
<td><%= link_to 'Show', subscription %></td>
<td><%= link_to 'Edit', edit_subscription_path(subscription) %></td>
<td><%= link_to 'Destroy', subscription, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
I hope that helps.

Rails calling a controller from another model's view

I have a post model and an upvote model.
upvote.rb
class Upvote < ActiveRecord::Base
has_one :user
belongs_to :post
end
# == Schema Information
#
# Table name: upvotes
#
# id :integer not null, primary key
# user_id :integer
# post_id :integer
# comment :text
# created_at :datetime
# updated_at :datetime
#
Now within posts/index I want to add an upvote for the current user and the post.
Some research pointed me to write a helper
posts_helper.rb
module PostsHelper
def upvote_post(post)
#upvote = Upvote.new
#upvote.user_id = current_user.id
#upvote.post_id = post.id
if #upvote.save
flash.now[:notice] = 'Upvote was successfully created.'
end
end
end
Inside my view I want to call the helper only on clicking a link but can't seem to get link_to working properly.
<% #posts.each do |post| %>
<tr>
<td><%= link_to "upboats" upvote_post(post) %></td>
<td><%= post.name %></td>
...
I get the error syntax error, unexpected tIDENTIFIER, expecting ')' and can't seem to find any good alternatives.
What am I missing here?
UPDATED
It was a comma. facepalm
Plenty of other issues, but that was what led to the error.
<% #posts.each do |post| %>
<tr>
<td><%= link_to "upboats", upvote_post(post) %></td>
<td><%= post.name %></td>
...
Closing open question.
It was a comma.
UPDATED
It was a comma. facepalm
Plenty of other issues, but that was what led to the error.
<% #posts.each do |post| %>
<tr>
<td><%= link_to "upboats", upvote_post(post) %></td>
<td><%= post.name %></td>
...

how to query in view ruby on rails

i have this in the controller
#ads = Ad.all(:joins => 'LEFT JOIN states ON ads.state_id = states.id')
but i have problem to query field of states table.
any idea?
<% #ads.each do |ad| %>
<tr>
<td><%= ad.title %></td> <- title is ad field.no problem
<td><%= ad.name %></td> <- name is states field.problem at here
</tr>
<% end %>
I don't think this will work unless you have associations set up. Unless performance is a concern, you may just want to use the association without joins
ad.rb
class Ad < ActiveRecord::Base
belongs_to :state
end
state.rb
class State < ActiveRecord::Base
has_many :ads
end
controller
#ads = Ad.all
view
<% #ads.each do |ad| %>
<tr>
<td><%= ad.title %></td>
<td>
<%= ad.state.name %>
</td>
</tr>
<% end %>
I think you need to put this: ads.state_id = states.id like this: #{ads.state_id = states.id}
The #{ } will evaluate the ruby code inside. Otherwise what you have is just text inside a string.
I'm not quite sure what your issue is, though, so I'm not totally sure that will fix it.