Rails 6 : NoMethodError and undefined method errors - ruby-on-rails

I am trying to add a post action button to upload a CSV to get data from CSV into postGreSQL database. But getting the following error(copied the error from request response of chrome devtools)
NoMethodError in Admin::UnitsController#import
undefined method `content_type' for nil:NilClass
Extracted source (around line #15):
#13 file = params[:file]
#14
*15 return redirect_to import_admin_tenant_site_units_path, notice: 'Only CSV please' unless file.content_type == "text/csv"
I have tried the following which is giving me the error.
Following the routes.rb
namespace :admin do
get '', to: 'dashboard#index', as: 'root'
# resourceful routes
resources :oauth_clients
resources :tenants do
resources :sites do
#resources :production_shifts
resources :units do
resources :log_data_fields, only: [:create, :index]
# collection route
collection do
post :import #post action
end
member do
get :logs
get :export_log
end
resources :reports
resources :grafana_dashboards
resources :data_adapters, except: [:show]
get 'data_adapters/start'
end
end
resources :users
resources :login_activities
# resources :login_activities
end
end
where post action "import" is of concern currently for this error.
I have included the import method's logic in the units_controller.rb as follows :
class Admin::UnitsController < Admin::BaseController
# import request(this is gonna be a POST action)
def import
logger.debug("*****Testing the logger.*****")
file = params[:file]
return redirect_to import_admin_tenant_site_units_path, notice: 'Only CSV please' unless file.content_type == "text/csv"
file = File.open(file)
csv = CSV.parse(file, headers: true)
binding.b
redirect_to import_admin_tenant_site_units_path, notice:"Imported tags !"
end
More things are to be done and I cannot even show complete code in public due to restricted reasons.
My rails debugging gem debug doesnt work either means it doesnt gets invoked even after mentioning it there as binding.b. Earlier it was working few days back but I dont know what mistakes I did.
And Sorry for poor explaining language.
Here I am also showing the frontend view code of the part where the csv file gets uploaded from. importtags.html.haml :
%p{:style => "color: green"}= notice
= form_with model:#log_data_field, url: import_admin_tenant_site_units_path, method: :post do |form|
- if #log_data_field.errors.any?
#error_explanation
%h2= "#{pluralize(#log_data_field.errors.count, "error")} prohibited this log_data_field from being saved:"
%ul
- #log_data_field.errors.full_messages.each do |message|
%li= message
= form.file_field :file, accept: ".csv"
<br>
<br>
-#button.btn.primary{:type => "submit", data: { disable_with: "Please wait..."}}
%button.btn.primary{:type => "submit"}
-#= form.button "Import"
= "Import"
PS : -# are indicating comments in the above haml code.

params[:file] is nil so the local file variable is going to be nil as well.
In the rails log you can see the params hash usually after Started POST and Processing by lines like Parameters: {...}
But you can always just use puts inside the controller to debug like p params to see its content.
I bet the file key inside the params hash is going to be nested under the name of your model.
Try file = params[:YOUR_MODEL_NAME][:file]
Maybe file = params[:log_data][:file]?:D

Related

Custom controller route to update column active to false

I am trying to link to a custom controller route action and I'm doing something wrong. I have a Document model that handles uploading documents to my CRUD app. I want users to be able to 'delete' something, but not actually delete it from the system, but rather update the column 'active' to false. Then if someone with admin privileges can go ahead an complete the deletion. This process is needed because the app gets audited and we do not want to accidentally delete uploaded files.
I can't get the custom update action (remove) to work. When I rake routes I see:
remove_documents PUT /documents/remove(.:format) document#remove
In my routes file (I'll a couple similar routes I'll want to add later so I used collection it up this way):
resources :documents do
collection do
put "remove", to: "document#remove", as: :remove
end
end
In the Documents index view:
<%= link_to remove_documents_url(document), :method => :put do %>
<span class="fa fa-trash text-danger"></span>
<% end %>
My Controller:
def remove
#document = Document.find(params[:id])
#document.active = false
#document.save
html { redirect_to(:back, :notice => 'Document was successfully removed.')}
end
The link works, but then I get the following error:
NameError at /documents/remove.75 uninitialized constant DocumentController
raise unless e.missing_name? qualified_name_for(parent, const_name)
end
end
name_error = NameError.new("uninitialized constant #{qualified_name}", const_name)
name_error.set_backtrace(caller.reject {|l| l.starts_with? __FILE__ })
raise name_error
end
# Remove the constants that have been autoloaded, and those that have been
# marked for unloading. Before each constant is removed a callback is sent
If you want the remove action on a specific Document, change the routes to :
resources :documents do
member do
put "remove", to: "documents#remove", as: :remove
end
end
which gives you : remove_document PUT /documents/:id/remove(.:format)
and use it like :
<%= link_to remove_document_path(document), :method => :put do %>
<span class="fa fa-trash text-danger"></span>
<% end %>

Following Rails tutorial, undefined method 'create' for nil:NilClass, with nested resource

I'm following the Rails tutorial and making changes where appropriate, with the intention that my tutorial project will become a full-fledged production app after the completion of the tutorial.
I've run into a snag with the second model portion of the tutorial. Here is how I've written my second model.
In my policy.rb:
class Policy < ApplicationRecord
has_one :insured
end
In my insured.rb:
class Insured < ApplicationRecord
belongs_to :policy
end
In my routes.rb:
resources :policies do
resource :insured
end
In my insureds_controller.rb:
def create
#policy = Policy.find(params[:policy_id])
# next line is raising the error
#insured = #policy.insured.create(insured_params)
redirect_to #insured
end
private
def insured_params
params.permit(:name, :address, :phone, :email)
end
I've inspected the #policy object with render plain: #policy.inspect and can confirm that ActiveRecord is retrieving the policy correctly. When I inspect the attributes of #policy, using render plain: #policy.attribute_names.inspect, I don't see an insured attribute, which I thought Rails was supposed to automatically manage for me. In the tutorial, an article has_many :comments, and a comment is supposedly easily created and associated with the parent article with this call: #article.comments.create(comment_params). I also noticed that the tutorial uses params.require(:comment).permit(...) while I have to use params.permit(...), after inspecting the params hash I saw that the :insured attributes existed in the top-level of the hash, instead of being tied to an :insured key within the hash.
I tried manually saving and assigning the #insured object like so:
def create
#policy = Policy.find(params[:policy_id])
#insured = Insured.new(insured_params)
if #insured.save
#policy.insured = #insured
redirect_to #insured
end
end
Only to run into the following error in my .../insureds/new.html.erb:
<h1>New Insured</h1>
<h1><%= #policy.policy_number %></h2>
<%= render 'form' %>
<%= link_to 'Cancel', policy_path(#policy) %>
Which derives from my partial form .../insureds/_form.html.erb:
# the following line raises the error
<%= form_with model: #insured, local: true do |form| %>
# html omitted for brevity
<% end %>
Error: 'undefined method insureds_path'. This is weird because when I inspect the HTML I can see the form action for this view is /policies/[:id]/insured.
Sorry for the massive wall of text, I wanted to show you guys that I did try to figure out what is going wrong.
There is an error in your config/routes.rb file:
resources :policies do
# change it for:
collection do
get 'insured', to: 'policies#show_insured', as: 'show_policy_insured'
# maybe unnecessary to be here
# get 'insured/new', to: 'insureds#new', as: 'new_policy_insured'
# post 'insured/create', to: 'insureds#create', as: 'create_policy_insured'
# delete 'insured/delete', to: 'insureds#delete', as: 'delete_policy_insured'
end
end
# add resources here
resources :insureds
In policy_controller.rb:
def show_insured # 'policy/:id/insureds/
end
In insureds_controller.rb:
def show # '/insureds/:id'
end
def create
...
redirect_to show_policy_insured && return if #insured_policy
end
# before_filter or before_action
#policy = Policy.find(params[:id])
#insured_policy = #policy.insured
Check it and run this to see your routes:
$ bundle exec rake routes
get /policies/:id/insured => 'policies_controller#show_insured'
get /insureds/:id => 'insureds_controller#show'
get /insured/new => 'insureds_controller#new'
post /insureds/create => 'insureds_controller#create'
delete /insureds/:id/delete => 'insureds_controller#delete'
#maguri, that's not all necessary. The stumbling block I was running into was that Rails couldn't automatically determine the correct routes. When I provided my own urls in the form_with declarations, everything went smoothly.
Observe the following change in my _form.html.erb for the Insured model, which belongs_to Policy, which has_one Insured.
<%= form_with model: #insured, url: policy_insured_path(#policy) local: true do |form| %>
In my updated insureds_controller.rb file, using #Phlip's suggestion:
def create
#policy = Policy.find(params[:policy_id])
#insured = #policy.create_insured(insured_params)
if #policy.insured.save
redirect_to policy_insured_path(params[:policy_id])
else
render 'new'
end
end
This allows me to keep routes.rb clean and simple:
resources :policies do
resource: insured
end
Thank you for your answer, it helped me discover the problem was with my routes.

Routing error in edit method

I'm writing a little Rails CMS and I'm a little stuck with a routing error. To begin with, I have a basic model called Entry, which other models are inheriting from. When I try to edit an existing model, it returns me an error
No route matches [PATCH] "/admin/posts/entries"
In my routes.rb in CMS plugin I have the following:
Multiflora::Engine.routes.draw do
root "dashboard#index"
scope "/:content_class" do
resources :entries
end
end
and in test app's routes.rb I have
mount Multiflora::Engine, at: '/admin'
In application_controller.rb I also tweaked routes a little:
def content_entries_path
entries_path(content_class: content_class.tableize)
end
helper_method :content_entries_path
def content_entry_path(entry)
entry_path(entry, content_class: content_class.tableize)
end
helper_method :content_entry_path
def new_content_entry_path
new_entry_path(content_class: content_class.tableize)
end
helper_method :new_content_entry_path
def edit_content_entry_path(entry)
edit_entry_path(entry, content_class: content_class.tableize)
end
helper_method :edit_content_entry_path
And in my show.html.erb I have this:
<%= link_to 'Edit', edit_content_entry_path(#entry) %>
When I navigate to edit_content_entry_path, it shows me edit page correctly, but when I try to save edited entry, it returns me an error stated above. When I run rake routes, it returns me the following:
entries GET /:content_class/entries(.:format) multiflora/entries#index
POST /:content_class/entries(.:format) multiflora/entries#create
new_entry GET /:content_class/entries/new(.:format) multiflora/entries#new
edit_entry GET /:content_class/entries/:id/edit(.:format) multiflora/entries#edit
entry GET /:content_class/entries/:id(.:format) multiflora/entries#show
PATCH /:content_class/entries/:id(.:format) multiflora/entries#update
PUT /:content_class/entries/:id(.:format) multiflora/entries#update
DELETE /:content_class/entries/:id(.:format) multiflora/entries#destroy
So, the error was in my edit.html.erb view -- instead of
<%= form_for(#entry, as: :entry, url: content_entry_path(#entry)) do |f| %>
I had
<%= form_for(#entry, as: :entry, url: entries_path do |f| %>
When I rewrote it, everything worked!

Routing Error with Ruby on Rails

I'm fairly new to Ruby on Rails and I'm having what seems like an easy problem but I can't seem to figure out what I have done wrong. My homepage has a button and when you click the button, its supposed to create an xml file with information from the database.
Button code:
<%= button_to "Create Google File", :action => :create_google_file %>
Controller code:
class ProductsController < ApplicationController
def new
end
def create_google_file
#products = Product.find(:all)
file = File.new('dir.xml','w')
doc = #products.to_xml
file.puts doc
file.close
end
end
The error I'm getting is
No route matches {:action=>"create_google_file", :controller=>"products"}
Add this to your config/routes.rb file
match "/create_google_file" => "products#create_google_file", :as => :create_google_file
And change the button to this
<%= button_to "Create Google File", create_google_file_path %>

Rails 3 can't find a custom action

I've seen this question answered here for Rails 2, but not Rails 3.
I have an app I'm running on localhost called Skynet, which provides one-click access to the scripts that I use regularly:
I have:
config/routes.rb:
Skynet::Application.routes.draw do
resources :robots do
member do
get "cleaner"
end
end
end
app/controllers/robots_controller.rb:
class RobotsController < ApplicationController
def index
respond_to do |format|
format.html
end
end
def cleaner
#output = ''
f = File.open("/Users/steven/Code/skynet/public/input/input.txt", "r")
f.each_line do |line|
#output += line
end
output = Sanitize.clean(#output, :elements => ['title', 'h1', 'h2', 'h3', 'h4', 'p', 'td', 'li'], :attributes => {:all => ['class']}, :remove_contents => ['script'])
newfile = File.new("/Users/steven/Code/skynet/public/output/result.txt", "w")
newfile.write(output)
newfile.close
redirect_to :action => "index"
end
end
(Will refactor later.)
In app/views/robots/index.html.haml I have:
= link_to "test", cleaner_robot_path
When I type rake routes, I get:
cleaner_robot GET /robots/:id/cleaner(.:format) {:controller=>"robots", :action=>"cleaner"}
So why, then, when I point my browser at http://localhost:3000/, do I get the following?
ActionController::RoutingError in Robots#index
Showing /Users/steven/Code/skynet/app/views/robots/index.html.haml where line #1 raised:
No route matches {:action=>"cleaner", :controller=>"robots"}
Extracted source (around line #1):
1: = link_to "test", cleaner_robot_path
Rails.root: /Users/steven/Code/skynet
Application Trace | Framework Trace | Full Trace
app/views/robots/index.html.haml:1:in `_app_views_robots_index_html_haml___2129226934_2195069160_0'
app/controllers/robots_controller.rb:4:in `index'
Request
Parameters:
None
Show session dump
Show env dump
Response
Headers:
None
you defined cleaner as a member function of the resource robots this means you have to supply an id as you can see in your rake routes message /robots/:id/cleaner(.:format)
So your link should look like
= link_to "test", cleaner_robot_path(some_id)
but
I think you want to use cleaner as a collection function:
Skynet::Application.routes.draw do
resources :robots do
collection do
get "cleaner"
end
end
end
then your link has to look like:
= link_to "test", cleaner_robots_path
Notice that robot is now plural!
According to your error message I guess you've tried that but used the collection in plural... Maybe you have to restart your server if you are in production mode.
You can read more about this routing stuff in the Ruby on Rails Guide

Resources