NoMethodError in Rails while saving data - ruby-on-rails

Checks_controller
class Checkscontroller < ApplicationController
def show
#check= Tester.find(params[:id])
end
def new
end
def create
#check = Tester.new(check_params)
#check.save
redirect_to #check
end
def check_params
params.require(:check).permit(:title, :description)
end
end
I am trying to save the data in 'checks' controller to 'Tester' model, getting "NoMethodError in ChecksController#create", undefined method tester_url' for#` while trying to save the data to my DB. There seems to be some issue on this line: "redirect_to #check".
Routes.rb
Rails.application.routes.draw do
get 'home/screen'
resources :checks
root 'home#screen'
end

EDIT: I see this answer got accepted. To anyone else looking at this: PLEASE DO NOT DO THIS WITHOUT A REALLY GOOD REASON.
Ok, so since you want to use the ChecksController for your Tester model, you'll have to add this to your routes: note that I'm assuming that you do not have a Check model, since I don't see it anywhere and youre using Tester as a check?
resources :testers, as: 'checks' controller: 'checks'
This line will make it so that /checks/1 goes to a Tester object with ID: 1, and use the ChecksController show method to show it
Old answer, for posterity
You're getting this error because you're missing routes for your Tester model in your routes.rb file.
You could add resources :testers to it and it will work. Of course you also already need AT LEAST your TestersController to exist with a show action
This error is occurring because when you redirect_to #check, Rails knows it's a Tester object and expects a route called tester to route to TestersController#show. It's attempting to use a helper method that rails creates for routes, called tester_url

Related

Nested resource from own controllers method - or create completely new controller?

Issue: When a user (when signed in) creates an order, they are sent to the OrderControllers show page which can only be accessed if signed in by both the buyer and seller. From here they can edit/update their order, etc.
We also have guest_user, someone who isn't signed in, and for them I need a order confirmation in the browser (I'm using Devise gem)
I have created a method:
def order_confirmation
In the OrdersController.
Although, how can I nest this within orders so the page knows which order to show.
Is this possible to nest methods under its' own controllers, or should i just create a small controller only for order confirmations?
For example: example.com/orders/1/order-confirmation
Maybe there are better ways to go about this other than just nesting and creating a controller?
I Tried:
resources :orders do
collection do
get 'order_confirmation'
end
end
With:
def order_confirmation
#order = Order.all.find(params[:id])
end
But it won't work how i want i t seems.
The rake routes gives me:
order_confirmation_orders GET /orders/order_confirmation(.:format)
How can i get?:
order_order_confirmation_orders GET /orders/id/order_confirmation(.:format)
I was able to figure this out from the help of this SO post:
Rails: Custom nested controller actions
By using:
resources :orders do
get 'order_confirmation', :on => :member
end
This creates:
order_confirmation_order GET /orders/:id/order_confirmation(.:format) orders#order_confirmation

undefined method `numbers' for nil:NilClass

Building a simple phone book app and have a concern regarding the following:
Each of my listed contacts has a number resource, and their relationship is defined in the routes file as follows:
config/routes.rb
resources :contacts do
resources :numbers
end
In my webapp thus far, I have it so that a user can create a contact and then create a number corresponding with that contact. I list the numbers for the contact, and when the user clicks on it (in order to route to the numbers#show page for that specific number, I get the following error:
NoMethodError in NumbersController#show
undefined method `numbers' for nil:NilClass
I've had this error a ton of times, and always it happened because the contact wasn't instantiated properly. But in my code, everything is being saved to db properly as per my rails console exploration. Below is the code throwing the error, found inside my numbers controller:
def set_number #to do item
#number = #contact.numbers.find(params[:id])
end
And the parameters being passed in, according to the error page, are the following:
Parameters:
{"contact_id"=>"1",
"id"=>"1"}
I set #contact via this method in the numbers controller:
def set_contact
#contact = Contact.find(params[:contact_id])
end
and I call it at the top as so:
before_action :set_contact
Given that there are parameters, and Rails console tells me both the contact and the number were saved properly, any idea what's wrong?
As I posted as a comment:
You have to have your before_action :set_contact before your before_action :set_number, otherwise you won't have the #contact when calling the :set_number.
All the before_action runs in the order that you added them :)
Cheers
Clearly the error seems to be in set_number method inside your controller. And the reason is #contact is nil.
So, as in above comments, your set_contact method may be running after set_number

Rails routing: Scope using a database field

I am creating an multitenant app based on ideas from Ryan Bigg's book "Multitenancy with Rails". In this book, the tenants has their own subdomain. This approach is not applicable in my case, so I'm trying to scope by a slug of the account's name instead.
So instead of URLs like http://account-name.myapp.com, i want http://myapp.mydomain.com/account-name/. The subdomain is reserved for the app itself, because I want to be able to have more than one app on my domain.
Here's a piece of my routes.rb:
scope module: 'accounts' do
resources :customers do
resources :notes
end
end
To achieve my goal, i try to follow the routing guide on rubyonrails.com (the last code snippet in chapter 4.5), and change the above code to:
scope ':slug', module: 'accounts' do
resources :customers do
resources :notes
end
end
slug is an attribute in the accounts table in the database, so if an account is called "My Business", the slug will typically be "my-business".
This change seems to correct my routes:
customers GET /:slug/customers(.:format)
.. but it also seems to break my site, as the slug is not fetched from the database. I can't seem to wrap my mind around how this scope':slug', module: 'accounts' works. Is Rails supposed to automatically recognize :slug as an attribute of the Accoounts table? If not, can anyone please help me find a way to use the account's slug in my URLs?
I have googled around for a couple of days now, and read numerous answers here on Stackoverflow. Nothing helped, so any pointers is greatly appreciated. :-)
EDIT:
The relevant controllers are set up like this:
controllers/accounts/base_controller.rb
controllers/accounts/customers_controller.rb
controllers/accounts/products_controlelr.rb
controllers/accounts_controller.rb
controllers/application_controller.rb
The accounts_controller.rb only has actions for new and create at this point.
The accounts/base_controller.rb look like this:
module Accounts
class BaseController < ApplicationController
before_action :authorize_user!
def current_account
#current_account ||= Account.find_by_slug(params[:slug])
end
...
end
end
I addded this to my Account model:
def to_param
slug
end
Before i tried to implement scope ':slug' in my routes, everyting worked when logged in users where directed to myapp.mydomain.com/dashboard and navigated to i.e. myapp.mydomain.com/customers. Now it works with myapp.mydomain.com/account-name/dashboard, but as soon as I try to navigate to a view that use helpers like new_customer_path, i get the error:
No route matches {:action=>"show", :controller=>"accounts/customers", :id=>nil, :slug=>#
I hope this makes my issue clearer. :-)
I am not sure whether your routes is set up correctly or not because you didn't post your controller source code, but basically how it works if very simple. If you are using the current routes you set up what you should do is create an account_customers_controller.rb file in controllers\account\folder, and it should look like this:
class Accounts::CustomersController < ActionController::Base
def show
#account = Account.find_by_slug(params[:slug])
...
end
end

Possible to Change Rails Routing Convention?

I'm wondering if it's possible to edit the default Rails routing convention to fetch a specific record based on a field that is not the ID?
For instance, instead of retrieving a specific record based on ID, with the verb/url combination:
GET /users/:id
Retrieve a specific record based on username, with the verb/url combination:
GET /users/:username
I don't see why this would be a problem theoretically, as long as usernames were required to be unique, but I'm having trouble understanding how to implement it based on the Rails Routing Guide.
I have gathered that I will need to add a line to my routes.rb file, to define a singular resource, just prior to:
resources :users
However, I'm having trouble understanding the syntax to accomplish this. Any help in understanding this would be greatly appreciated.
Yes it is possible and they are called Non Restful Routes in the rails documentation
A trivial example is doing the below in your routes.rb
get ':users/:show/:username', controller: "users", action: "show"
and in your UsersController you have a show action that looks like this:
def show
if params[:id].present?
#user = User.find(params[:id])
elsif params[:username].present?
#user = User.find_by(username: params[:username])
end
end
This way you support showing by id and username, if you want do disable support for either of them, modify the if clause as you wish
I think you are looking to change the to_param method like so:
class User < ActiveRecord::Base
def to_param
"#{id} #{name}".parameterize
end
end
This would give the url as: /user/id-name. If you want to get rid of the id before the name it gets a little more complicated. If you were just to remove it, it will more than likely break since ActiveRecord needs the id first for finds.
To get around this I would suggest using FriendlyId gem: https://github.com/norman/friendly_id
There is also a RailsCast showing how to use Friendly_id but its pretty straight forward.
The routes does not care if it is an ID or username.
It is really how you find it in the controller.
Just in the user show controller:
def show
#user = User.find_by_username params[:id]
end

Rails4 new template .erb creation Not Happening

I have generated scaffold and created a view called "appointment"
I wanted to added a template .erb file called inbox_mail.html.erb in appointment folder.
I did setting like this.
route.rb
get '/appointments/inbox_mail'
In appointment controller
class AppointmentsController < ApplicationController
def inbox_mail
end
end
Now running the link 3000/appointments/inbox_mail
but giving rise error as,
Mongoid::Errors::DocumentNotFound in AppointmentsController#show
Problem: Document(s) not found for class Appointment with id(s) delete_appointment. Summary: When calling Appointment.find with an id or array of ids, each parameter must match a document in the database or this error will be raised. The search was for the id(s): delete_appointment ... (1 total) and the following ids were not found: delete_appointment. Resolution: Search for an id that is in the database or set the Mongoid.raise_not_found_error configuration option to false, which will cause a nil to be returned instead of raising this error when searching for a single id, or only the matched documents when searching for multiples.
Help me in Rails4...!!!!
May be this is b'z of
def set_appointment
#appointment = Appointment.find(params[:id])
end
Yes, it is because of set_appointment method. I guess you should add :id segment to your route, like
match '/appointments/delete_appointment/:id', to: 'appointments#delete_appointment', via: :get
and this should work.
Delete something shouldn't be done through GET, you should use the DELETE method. So, when you create the link with "link_to" you should do:
link_to 'Delete appointment', delete_appointment_path(#appointment.id), method: :delete
you need a route like:
delete '/appointments/delete_appointment/:id', to: 'appointments#delete_appointment'
Then rails will take care of that and do a DELETE request with the appointment's id, then on your controller you can use #appointment = Appointment.find(params[:id])
You may want some kind of validation to render a "not found" template:
def delete_appointment
unless #appointment = Appointment.find(params[:id])
redirect_to appointment_not_found_path #something_like_that
end
end
EDIT: it looks like some before_filter is messing up there too, you talked about "delete_appointment", the error say the action called is "show" and you copied the code for the action/before_filter "set_appointment", check that first
EDIT 2: you say you are not doing any delete, then use get, the important part is the :id on the url if you need to find an appointment by an ID you need that on the url. If you don't need the ID then check your before filters, I guess you have something like
before_filter :set_appointment
you may want to skip that filter on delete_appointment
before_filter :set_appointment, except: :delete_appointment

Resources