I'm working on an application where I've had to put together some custom rails parameters for the routes and I keep getting no route found errors when I try to access the page associated with the show method. The application is allowing me to reach my edit pages, so I know it's working on some level but I have to have an error I'm not seeing somewhere that's messing with the normal view. The custom parameters rely on an :identifier that has been custom created for each object. Because the application manages several institutions, all with their objects and files, I've had to right several different sets of routes to handle each different thing. The routes for institutions seem to be working fine, but the second set, for :intellectual_objects are the ones that aren't working.
This is my routes file (irrelevant parts excluded):
Fluctus::Application.routes.draw do
get "institutions/:institution_identifier/objects", to: 'intellectual_objects#index', as: :institution_intellectual_objects, :constraints => { :institution_identifier => /[\w+\.]+/ }
post "institutions/:institution_identifier/objects", to: 'intellectual_objects#create', :constraints => { :institution_identifier => /[\w+\.]+/ }
#Intellectual Object Routes
#get "objects/:institution_identifier", to: 'intellectual_objects#index', as: :institution_intellectual_objects, :constraints => { :institution_identifier => /[\w+\.]+/ }
#post "objects/:institution_identifier", to: 'intellectual_objects#create', :constraints => { :institution_identifier => /[\w+\.]+/ }
patch "objects/:intellectual_object_identifier", to: 'intellectual_objects#update', :constraints => { :intellectual_object_identifier => /[\w+\/\.]+/ }
put "objects/:intellectual_object_identifier", to: 'intellectual_objects#update', :constraints => { :intellectual_object_identifier => /[\w+\/\.]+/ }
delete "objects/:intellectual_object_identifier", to: 'intellectual_objects#destroy', :constraints => { :intellectual_object_identifier => /[\w+\/\.]+/ }
get "objects/:intellectual_object_identifier/edit", to: 'intellectual_objects#edit', as: :edit_intellectual_object, :constraints => { :intellectual_object_identifier => /[\w+\/\.]+/ }
get "objects/:intellectual_object_identifier/events", to: 'events#index', as: :intellectual_object_events, :constraints => { :intellectual_object_identifier => /[\w+\/\.]+/ }
post "objects/:intellectual_object_identifier/events", to: 'events#create', :constraints => { :intellectual_object_identifier => /[\w+\/\.]+/ }
get "objects/:intellectual_object_identifier", to: 'intellectual_objects#show', as: :intellectual_object, :constraints => { :intellectual_object_identifier => /[\w+\/\.]+/ }
#post "objects/institution_identifier/:intellectual_object_identifier/data", to: 'generic_files#create', as: intellectual_object_generic_files, :constraints => { [:intellectual_object_identifier, :institution_identifier] => /[\w+\.]/ }
#patch "objects/institution_identifier/:intellectual_object_identifier/data/:filename", to: 'generic_files#update', :constraints => { [:intellectual_object_identifier, :institution_identifier] => /[\w+\.]/ }
Blacklight.add_routes(self)
mount Hydra::RoleManagement::Engine => '/'
root :to => "catalog#index"
end
This is my IntellectualObject Controller:
class IntellectualObjectsController < ApplicationController
before_filter :authenticate_user!
#load_and_authorize_resource :institution, only: [:index, :create]
load_and_authorize_resource :through => :institution, only: :create
#load_and_authorize_resource except: [:index, :create]
before_filter :set_object, only: [:show, :edit, :update, :destroy]
before_filter :set_institution, only: [:index, :create]
include Aptrust::GatedSearch
apply_catalog_search_params
include RecordsControllerBehavior
self.solr_search_params_logic += [:for_selected_institution]
def update
if params[:counter]
# They are just updating the search counter
search_session[:counter] = params[:counter]
redirect_to :action => "show", :status => 303
else
# They are updating a record. Use the method defined in RecordsControllerBehavior
super
end
end
def destroy
resource.soft_delete
respond_to do |format|
format.json { head :no_content }
format.html {
flash[:notice] = "Delete job has been queued for object: #{resource.title}"
redirect_to root_path
}
end
end
protected
# Override Hydra-editor to redirect to an alternate location after create
def redirect_after_update
intellectual_object_path(resource)
end
def self.cancan_resource_class
CanCan::ControllerResource
end
private
def for_selected_institution(solr_parameters, user_parameters)
#puts "In for_selected_institution------------------------------------------"
#puts params[:institution_identifier]
#puts params[:intellectual_object_identifier]
if(params[:institution_identifier])
institution = Institution.where(desc_metadata__institution_identifier_tesim: params[:institution_identifier]).first
else
io = IntellectualObject.where(desc_metadata__intellectual_object_identifier_tesim: params[:intellectual_object_identifier]).first
institution = io.institution
end
#puts "INSTITUTION: #{institution.id}"
solr_parameters[:fq] ||= []
solr_parameters[:fq] << ActiveFedora::SolrService.construct_query_for_rel(is_part_of: "info:fedora/#{institution.id}")
end
# Override Blacklight so that it has the "institution_identifier" set even when we're on a show page (e.g. /objects/foo:123)
def search_action_url options = {}
institution_intellectual_objects_path(params[:institution_identifier] || #intellectual_object.institution.institution_identifier)
end
def set_institution
if params[:institution_identifier].nil? || Institution.where(desc_metadata__institution_identifier_tesim: params[:institution_identifier]).empty?
redirect_to root_url
flash[:alert] = "Sonething wrong with institution_identifier."
else
#institution = Institution.where(desc_metadata__institution_identifier_tesim: params[:institution_identifier]).first
authorize! [:create, :index], #institution if cannot? :read, #institution
end
end
def set_object
if params[:intellectual_object_identifier].nil? || IntellectualObject.where(desc_metadata__intellectual_object_identifier_tesim: params[:intellectual_object_identifier]).empty?
redirect_to root_url
flash[:alert] = "Something wrong with intellectual_object_identifier."
else
io_options = IntellectualObject.where(desc_metadata__intellectual_object_identifier_tesim: params[:intellectual_object_identifier])
io_options.each do |io|
if params[:intellectual_object_identifier] == io.intellectual_object_identifier
#intellectual_object = io
#institution = #intellectual_object.institution
end
end
if #intellectual_object.nil?
redirect_to root_url
flash[:alert] = "The object you requested does not exist."
end
#authorize! [:show, :edit, :update, :destroy], #institution if cannot? :read, #institution
end
end
end
I'm getting the following error when I try to access the show route (for example: localhost:3000/objects/test.org/126939282):
ActionController::UrlGenerationError in IntellectualObjects#show
Showing /Users/kec6en/HydraApp/fluctus/app/views/intellectual_objects/_facet_limit.html.erb where line #11 raised:
No route matches {:action=>"index", :intellectual_object_identifier=>"columbia.edu/798d6e812041532c", :controller=>"intellectual_objects", :f=>{"institution_name_ssi"=>["Columbia University"]}}
The parameters are showing:
{"intellectual_object_identifier"=>"columbia.edu/798d6e812041532c"}
And I'm getting this error when I run my spec tests on the IntellectualObjectController
Failure/Error: get :show, intellectual_object_identifier: obj1
ActionController::UrlGenerationError:
No route matches {:intellectual_object_identifier=>"kaulkedurgan.org13/39b1eb47-da8b-4145-b03b-5f1851407012", :controller=>"intellectual_objects", :action=>"show"}
I just don't understand because the routes are there, and some of them appear to be working in the application, but every single one is failing in my spec tests. Any and all help is appreciated. Thank you.
Your route to intellectual_objects#index has the constraint that the :institution_identifier should match /[\w+\.]+/, but columbia.edu/798d6e812041532c does not match that regexp. Even when you add \/ to your regexp, I am pretty sure that the slash will confuse Rails routing system.
Perhaps you want to change the route to something like this
get "institutions/:institution_identifier/:some_id/objects",
to: 'intellectual_objects#index',
as: :institution_intellectual_objects,
constraints: { institution_identifier: /[\w+\.]+/ }
And than provide columbia.edu (institution_identifier) and 798d6e812041532c (some_id) as separate values.
According to your error:
No route matches {:action=>"index"
It seems you're trying to access the index action?
Being honest, I couldn't bring myself to look through all your routes (you may want to cut out the irrelevant stuff?)
How are you calling the routes with link_to?
Related
I'm trying to code a spec for a method who redirect to a specific path when the user access to provider/plans and provider/prospects
I was trying with many path combinations in the before group, i was trying with this.
before { get :provider_plans_index_path }
before { get :provider_index_plans_path}
before { get :provider_plans_path}
before { get :provider_index_path}
before { get :provider_plans_path}
before { get :provider_planes_path}
base_controller.rb
class Provider::BaseController < ActionController::Base
layout 'provider'
before_action :allowed_pages
def allowed_pages
redirect_to financial_dashboard_path if !requested_action?(params[:controller])
end
def requested_action?(data)
regexp = %r{
^(provider/plans)|
(provider/prospects)$
}x
data.match?(regexp)
end
end
base_controller_spec.rb
require 'rails_helper'
describe Provider::BaseController, type: :controller do
let(:provider) { create(:provider) }
let(:financial) { create(:financial, provider: provider) }
let(:user) { provider.user }
before { login_user user }
describe 'GET plans' do
context 'with not allowed url' do
before { get :provider_planes_path}
it { should redirect_to financial_dashboard_path}
end
end
end
routes.rb
namespace :provider do
get '', to: 'dashboard#index'
get 'dashboard', to: 'dashboard#index'
resources :plans, only: [:index, :create, :update], path: 'planes'
resources :prospects, only: [:index, :show, :create, :update], path: 'prospectos' do
get 'diagnostico', to: 'prospects#show', on: :member, as: :general
patch 'diagnostico', to: 'prospects#update', on: :member
get 'configuracion', to: 'prospects#configuration', on: :member, as: :configuration
end
end
I'm getting this error with all the combinations
ActionController::UrlGenerationError:
No route matches
For me the solution was call the action in spec via another controller
context 'with not allowed url' do
before do
#controller = Provider::PlansController.new
get :index
end
it { should redirect_to financial_dashboard_path }
end
Is there a “standard” approach to receiving (potentially nested) a JSON:API POST object in Rails?
The JSON:API spec uses the same format for GET / POST / PUT, etc, but rails seems to need *_attributes and accepts_nested_attributes_for. These seem incompatible.
I feel like what I'm doing must be somewhat common, yet I'm having trouble finding documentation. I'm wanting to use a React/Redux app that communicates with a Rails app using the JSON:API spec. I'm just not sure how to handle the nested associations.
You can active_model_serializer gem's Deserialization functionality.
From the docs of the gem:
class PostsController < ActionController::Base
def create
Post.create(create_params)
end
def create_params
ActiveModelSerializers::Deserialization.jsonapi_parse(params, only: [:title, :content, :author])
end
end
The above can work with the below JSON API payload:
document = {
'data' => {
'id' => 1,
'type' => 'post',
'attributes' => {
'title' => 'Title 1',
'date' => '2015-12-20'
},
'relationships' => {
'author' => {
'data' => {
'type' => 'user',
'id' => '2'
}
},
'second_author' => {
'data' => nil
},
'comments' => {
'data' => [{
'type' => 'comment',
'id' => '3'
},{
'type' => 'comment',
'id' => '4'
}]
}
}
}
}
The entire document can be parsed without specifying any options:
ActiveModelSerializers::Deserialization.jsonapi_parse(document)
#=>
# {
# title: 'Title 1',
# date: '2015-12-20',
# author_id: 2,
# second_author_id: nil
# comment_ids: [3, 4]
# }
I saw these longs threads/issues discussions #979 and #795 on JSON:API repo days ago, that aparently seems that JSON API don't have a true solution for accepts_nested_attributes_for.
I don't know if it is the better solution but the work around to that is disposing a route to your belongs_to and has_many/has_one associations.
Something like that:
Your routes.rb:
Rails.application.routes.draw do
resources :contacts do
resource :kind, only: [:show]
resource :kind, only: [:show], path: 'relationships/kind'
resource :phones, only: [:show]
resource :phones, only: [:show], path: 'relationships/phones'
resource :phone, only: [:update, :create, :destroy]
# These relationships routes is merely a suggestion of a best practice
resource :phone, only: [:update, :create, :destroy], path: 'relationships/phone'
resource :address, only: [:show, :update, :create, :destroy]
resource :address, only: [:show, :update, :create, :destroy], path: 'relationships/address'
end
root 'contacts#index'
end
Them implement your controllers.
The phones_controller.rb following the example above:
class PhonesController < ApplicationController
before_action :set_contacts
def update
phone = Phone.find(phone_params[:id])
if phone.update(phone_params)
render json: #contact.phones, status: :created, location: contact_phones_url(#contact.id)
else
render json: #contact.errors, status: :unprocessable_entity
end
end
# DELETE /contacts/1/phone
def destroy
phone = Phone.find(phone_params[:id])
phone.destroy
end
# POST contacts/1/phone
def create
#contact.phones << Phone.new(phone_params)
if #contact.save
render json: #contact.phones, status: :created, location: contact_phones_url(#contact.id)
else
render json: #contact.errors, status: :unprocessable_entity
end
end
# GET /contacts/1/phones
def show
render json: #contact.phones
end
private
# Use callbacks to share common setup or constraints between actions.
def set_contacts
#contact = Contact.find(params[:contact_id])
end
def phone_params
ActiveModelSerializers::Deserialization.jsonapi_parse(params)
end
end
By doing that you should be able to request a Phone POST normally through a contact separately, like so:
POST on http://localhost:3000/contacts/1/phone with the body:
{
"data": {
"type": "phones",
"attributes": {
"number": "(+55) 91111.2222"
}
}
}
The response or GET on http://localhost:3000/contacts/1/phones:
{
"data": [
{
"id": "40",
"type": "phones",
"attributes": {
"number": "(55) 91111.2222"
},
"relationships": {
"contact": {
"data": {
"id": "1",
"type": "contacts"
},
"links": {
"related": "http://localhost:3000/contacts/1"
}
}
}
}
]
}
Hope that answer
Cant seem to get friendly_id to work with with my categories and subcategories. I am using the friendly_id gem as well.
Here is my categories controller
class CategoriesController < ApplicationController
def index
#categories = Category.all
#oval = #categories[0]
#atv = #categories[1]
#boat = #categories[2]
#fab = #categories[3]
#chassis = #categories[4]
#classic = #categories[5]
#dirt = #categories[6]
#dragracing = #categories[7]
#audio = #categories[8]
#engine = #categories[9]
#tune = #categories[10]
#enginecom = #categories[11]
#exhaust = #categories[12]
#golfcart = #categories[13]
#hotrod = #categories[14]
#karts = #categories[15]
#modern = #categories[16]
#motorcycle = #categories[17]
#muscle = #categories[18]
#offroad = #categories[19]
#racingitem = #categories[20]
#accessories = #categories[21]
#position = #categories[22]
#racingeq = #categories[23]
#roadracing = #categories[24]
#safety = #categories[25]
#snowmobile = #categories[26]
#tw = #categories[27]
#tools = #categories[28]
#rvs = #categories[29]
#tractor = #categories[30]
#trailer = #categories[31]
#transmission = #categories[32]
#truckpart = #categories[33]
#drift = #categories[34]
#import = #categories[35]
end
For example my url right now is
localhost:3000/categories/4/subcategories/27
I want it to be
localhost:3000/categories/dragracing/subcategories/pro-mod
Here is my routes
Rails.application.routes.draw do
resources :channels
resources :discussions do
resources :replies
end
resources :comments
resources :blogs
mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
mount ActionCable.server => '/cable'
get 'users/show'
get 'about', to: 'pages#about'
get 'directory', to: 'pages#directory'
get 'contact', to: 'pages#contact'
get 'privacy', to: 'pages#privacy'
get 'faq', to: 'pages#faq'
get '/myads', to: 'posts#myads'
get 'partner', to: 'pages#partner'
get '/sitemap' => 'sitemap#index', defaults: {format: "xml"}
root 'categories#index'
devise_for :users, path: '', path_names: { sign_in: 'login', sign_out: 'logout', sign_up: 'register' }, controllers: { registrations: "registrations"}
resources :users
resources :mes
resources :pricing, only:[:index]
resources :posts
resource :subscription
resources :categories do
resources :subcategories
end
end
The descripition of the route you are trying to use is:
# /categories/:category_id/subcategories/:id
This means that whatever you send instead of :category_id will be available in your controller as params[:category_id], the same for :id => params[:id].
So, if you send /categories/dragracing/subcategories/pro-mod, your parameters will be:
{ 'category_id' => 'dragracing', 'id' => 'pro-mod' }
As your code currently stands, this endpoint will be routed to subcategories#show.
# category_subcategory GET /categories/:category_id/subcategories/:id(.:format) subcategories#show
So you need a controller for that. You don't need to send ids or numbers whatsoever in the URL, you just need to handle them correctly:
class SubcategoriesController < ApplicationController
def show
#category = Category.friendly.find params[:category_id] # dragracing
#subcategory = Subcategory.friendly.find params[:id] # pro-mod
end
end
I'm new to programming and sorry if this is a stupid question. I'm writing a test for controllers in Ruby on Rails. The test is expecting a parameter but I'm not sure how to do that. When I run the test with rspec I get the error you see in the title.
This is PART of the controller's code:
class DemographicDetailController < ApplicationController
#before_filter :authorize
include ::Demographic
def show
#cinema_id = params[:cinema_id]
#cinema = Cinema.find(#cinema_id)
#cinema_name = #cinema.name
#cinmea_address = #cinema.address.full_street_address
#cinema_authority_id = #cinema.address.post_code.local_authority_id
#c_working_age = Population.where(:local_authority_id => #cinema_authority_id , :year => Population.maximum("year")).first
#c_working_age = #c_working_age.working_age_16_to_64
#c_total_population = totalpopulation(#cinema_authority_id)
#c_average_income = latestaverageincome(#cinema_authority_id)
#all_cinemas = Cinema.all
(...)
end
and this is the test I wrote for show method:
describe "Demographic" do
context "when testing the DemographicDetail controller" do
#let(:params) { { disabled: false } }
let(:cinema_id) { create(:cinema) }
it "should show demoraphic details successfully" do
get :show, params: { id: #cinema_id }
assert_response :success
end
end
This is the route:
controller :demographic_detail do
get '/demographic_detail/show/:cinema_id' => :show
end
Try this
modify the route as
get '/demographic_detail/show' => 'demographic_detail#show'
Try this:
get '/demographic_details/:cinema_id' => 'demographic_detail#show'
or
controller :demographic_detail do
get '/demographic_detail/:cinema_id' => :show
end
I don't understand why I'm getting this error message when I run RSpec:
Failure/Error: post :create
ActionController::RoutingError:
No route matches {:controller=>"stocks", :action=>"create"}
The controller stocks exists, the action create exists, and the route it should be using is this:
match 'stocks/:user_id' => 'stocks#create', :via => :post, :as => :query
Route File:
FruthScreener::Application.routes.draw do
root :to => 'stocks#index' # add user_id
match 'stocks/:user_id' => 'stocks#create', :via => :post, :as => :query
match 'stocks/:user_id' => 'stocks#destroy', :via => :delete, :as => :reset
match 'stocks/:user_id/update' => "stocks#update_index", :via => :post
Stock Controller: (Yes, this will be DRYed up)
class StocksController < ApplicationController
def index
#user = User.create
#user_id_num = #user.id
#user.stocks = Stock.all
#user.save
selected_user_stocks = (UserStock.where("user_id = #{#user_id_num} AND selected = true")).take(25)
#stocks = UserStock.convert_to_stocks(selected_user_stocks)
#pages = Pagination.determine_num_pages(#user.stocks)
end
def update_index
#user_id_num = params[:user_id]
#user = User.find(#user_id_num)
selected_user_stocks = UserStock.where("user_id = #{#user_id_num} AND selected = true")
#stocks = UserStock.convert_to_stocks(selected_user_stocks)
#pages = Pagination.determine_num_pages(#stocks)
#stocks = Stock.display(#stocks, params[:pageNumber].to_i)
render partial: 'stock_data'
end
def create
UserStock.eliminate_stocks(params) # thinking it's like "creating" a new batch of stocks
#user_id_num = params[:user_id]
#user = User.find(#user_id_num)
selected_user_stocks = UserStock.where("user_id = #{#user_id_num} AND selected = true")
#stocks = UserStock.convert_to_stocks(selected_user_stocks)
#pages = Pagination.determine_num_pages(#stocks)
#stocks = Stock.display(#stocks, 1)
render partial: 'stock_data'
end
def destroy
stocks_to_reset = UserStock.where("user_id = #{params[:user_id]}")
stocks_to_reset.each do |user_stock|
user_stock.selected = true
user_stock.save
end
#user_id_num = params[:user_id]
#user = User.find(#user_id_num)
selected_user_stocks = UserStock.where("user_id = #{#user_id_num} AND selected = true")
#stocks = UserStock.convert_to_stocks(selected_user_stocks)
#pages = Pagination.determine_num_pages(#stocks)
#stocks = Stock.display(#stocks, 1)
render partial: 'stock_data'
end
end
Stock Controller Spec: (test at bottom is failing)
require 'spec_helper'
RSpec.configure do |config|
config.infer_spec_type_from_file_location!
end
describe StocksController do
context "index" do
before do
#user_count = User.all.count
#stock_count = Stock.all.count
get :index
end
it "should create a new user" do
expect(User.all.count).to eq(#user_count + 1)
end
it "should associate all stocks with the user" do
expect(User.last.stocks.count).to eq(#stock_count)
end
end
context "create" do # investigate why this isn't working...
it "should render the stock_list partial" do
user = User.create
post :create
response.should render_template(partial: "stock_list")
end
end
end
Thanks!!
match 'stocks/:user_id' => 'stocks#create', :via => :post, :as => :query
tells us that it needs :user_id to be a valid route.
post :create
has no :user_id... so it doesn't refer to a valid route.
I'd change it to
post :create, :user_id => user.id
post :create, params: {user_id: user.id}