link_to nested resource route can't find ID - ruby-on-rails

The link_to in my user name is creating an error and I don't know why.
Error:
Couldn't find StripeAccount without an ID
Controller:
this is inside a separate controller from the StripeAccount controller
def settings
#user = current_user.id
#stripe_account = StripeAccount.find(params[:stripe_account_id])
end
I have tried "#stripe_account = StripeAccount.find(params[:id])" with the same error
View:
<%= link_to user_stripe_account_path(#user, #stripe_account) %>
I have tried using #stripe_account.id, etc.
Models:
stripe_account::
belongs_to :user, optional: true
user::
has_one :stripe_account
Routes:
resources :users do
resources :stripe_accounts
end
Error when i try loading the /settings page:
Here's the CMD from when I use: #stripe_account = StripeAccount.find(params[:stripe_account_id])
app/controllers/dashboard_controller.rb:18:in `settings'
Started GET "/settings" for 127.0.0.1 at 2018-11-17 06:27:04 -0500
Processing by DashboardController#settings as HTML
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 2], ["LIMIT", 1]]
↳ app/controllers/dashboard_controller.rb:17
Completed 404 Not Found in 3ms (ActiveRecord: 0.3ms)
ActiveRecord::RecordNotFound (Couldn't find StripeAccount without an ID):
app/controllers/dashboard_controller.rb:18:in `settings'
When i use #stripe_account = StripeAccount.find(params[:id])
ActiveRecord::RecordNotFound (Couldn't find StripeAccount without an ID):
app/controllers/dashboard_controller.rb:18:in `settings'
Started GET "/settings" for 127.0.0.1 at 2018-11-17 06:28:21 -0500
Processing by DashboardController#settings as HTML
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 2], ["LIMIT", 1]]
↳ app/controllers/dashboard_controller.rb:17
Completed 404 Not Found in 3ms (ActiveRecord: 0.3ms)
ActiveRecord::RecordNotFound (Couldn't find StripeAccount without an ID):
app/controllers/dashboard_controller.rb:18:in `settings'
What am i doing incorrectly?
The only issue i can think of that may be happening is rails/ruby is finding the API ID from stripe_account, which contains a bunch of information from stripe... if so, is there a way i can specifically state using the ID from the table?

You should be able to do #stripe_account = current_user.stripe_account if you wan't to set the variable to the current_user's stripe account (you have no id param on the request). And I recommend you to use #user = current_user or #user_id = current_user.id since it's confusing to read a variable named #user that has an integer value.
When you define "StripeAccount belongs_to User", by default (it's the convention) ActiveRecord looks for a user_id column on stripe_accounts table.
I'd recommend you to read this https://guides.rubyonrails.org/association_basics.html. It explains all types of associations and you can configure your associations even if they are not conventional (different class names, no _id column, etc).

After many attempts, i got one way to work. I'm not sure how efficient this is and i will explore more options.
This ended up working how i wanted to:
#stripe_account = StripeAccount.find_by(params[:id])
The key was using ".find_by" and not ".find". This allows the link_to to operate and goes to the right location.

Related

How to pass data from view that came from an external API to a controller?

So I want to pass a data from a view that was rendered from an external api to a controller to be able to save the ID to a model/database table.
This is my view:
<h1>Heroes</h1>
<% #response.each do |hero| %>
<div class = "hero_wrap">
<div class = "img">
<img src="https://api.opendota.com<%= hero["img"]%>", id ="hero_img"/>
</div>
<div class = "fave_container">
<%= link_to(image_tag('fave.png', class: "fave_img"), new_hero_path) %>
<%= hero["id"]%>
</div>
<div class = "hero_name">
<%= hero["localized_name"] %>
</div>
</div>
<% end %>
My controller:
# heroes_controller
class HeroesController < ApplicationController
def index
#response = HTTParty.get("https://api.opendota.com/api/heroStats")
end
def create
#hero= Hero.new(params[:id])
#hero.save
redirect_to #hero
end
end
Routes:
Rails.application.routes.draw do
get '/signup', to: 'users#new'
get 'pages/home'
resources :pro_players
devise_for :users
resources :heroes
resources :users
root 'pages#home'
end
My hero model doesn't contain anything yet, I just want to pick the hero id and save it to my database.
this is my web app
server log upon clicking the star icon with link:
Started GET "/heros?custom_hero_id=1&method=post" for 127.0.0.1 at
2018-10-15 09:20:53 +0800
Processing by HerosController#index as HTML
Parameters: {"custom_hero_id"=>"1", "method"=>"post"}
User Load (0.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
↳/home/don/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/activerecord-
5.2.1/lib/active_record/log_subscriber.rb:98
Rendering heros/index.html.erb within layouts/application
Rendered heros/index.html.erb within layouts/application (42.2ms)
Rendered layouts/_header.html.erb (1.1ms)
Rendered layouts/_footer.html.erb (0.4ms)
Completed 200 OK in 770ms (Views: 83.3ms | ActiveRecord: 0.7ms)
Updated log:
Started POST "/heros?custom_hero_id=21" for 127.0.0.1 at 2018-10-15 10:13:17 +0800
Processing by HerosController#create as HTML
Parameters: {"authenticity_token"=>"PHDEXdDmPhPX+VdloU2y6yONY5HN5wI2lIfOaSbSKj9+RvTO5Ua3QPuTcreLZtGNDFPaSOXhDVyve6J69+1CQQ==", "custom_hero_id"=>"21"}
User Load (0.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
↳/home/don/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/activerecord-5.2.1/lib/active_record/log_subscriber.rb:98
(0.2ms) BEGIN
↳ app/controllers/heros_controller.rb:9
Hero Create (0.4ms) INSERT INTO "heros" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id" [["created_at", "2018-10-15 02:13:17.032248"], ["updated_at", "2018-10-15 02:13:17.032248"]]
↳ app/controllers/heros_controller.rb:9
(42.3ms) COMMIT
↳ app/controllers/heros_controller.rb:9
Redirected to http://localhost:3000/heros/10
Completed 302 Found in 59ms (ActiveRecord: 46.9ms)
Started GET "/heros/10" for 127.0.0.1 at 2018-10-15 10:13:17 +0800
AbstractController::ActionNotFound (The action 'show' could not be found for HerosController):
The :id attribute is by default a auto-increment attribute of datatype integer which sets its value under the hood whenever a new instance of the model is created. There are several ways to override the its behavior or setting its value explicitly, but considering that you are fairly new to the technology I don't recommend those for you. Instead I recommend a simpler solution of using another attribute to store hero["id"]
Steps:
1) Generate a migration to create a new column(say custom_hero_id) in the heroes table
rails g migration add_custom_hero_id_to_heroes custom_hero_id:integer
and do rake db:migrate
2) Change
<%= link_to(image_tag('fave.png', class: "fave_img"), new_hero_path) %>
to
<%= link_to(image_tag('fave.png', class: "fave_img"), heroes_path(custom_hero_id: hero["id"]), method: :post) %>
3) Finally change your create action to below
def create
#hero= Hero.create(custom_hero_id: params[:custom_hero_id])
redirect_to #hero
end
Update:
Due to unknown reason, custom_hero_id isn't saving to the DB. Probably due to forbidden attributes error. Try changing it to
def create
#hero = Hero.new(hero_params)
if #hero.save
redirect_to #hero
end
end
private
def hero_params
params.permit(:custom_hero_id)
end
Do you want to store the hero id or it's name ?
I would advise to create a method in your heroe model. Something like
// heroe.rb
def save_api_heroes_to_db(response)
response.each do |hero|
unless hero[:localized_name].exists?
hero.create(id: hero[:id], name: hero[:localized_name], image: hero[:img])
end
end
end
This method will save the heroe id, name and image in your database (unless it already exists).
You just have to call it in your index method, in your heroe controller.
Hope that helps.

Confusion in object ID when editing and deleting

Specify the ID of the desired object, while the first object of the model is always deleted/edited. For the first time I met such a problem, checked everything. What's wrong?
Started DELETE "/questions/6" for 127.0.0.1 at 2018-07-05 10:48:13 +0300
Processing by QuestionsController#destroy as HTML
Parameters: {"authenticity_token"=>"luh7ShhQ9pWka7wmWMnG4WMQVAnKRjtAJwn0s5at8/GBDOtFjUwZEF70o8hOFOaAN+pVB592V1+egH/PDJVUVA==", "id"=>"6"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
↳ /Users/gorbunov/.rvm/gems/ruby-2.4.1/gems/activerecord-5.2.0/lib/active_record/log_subscriber.rb:98
Question Load (0.1ms) SELECT "questions".* FROM "questions" WHERE (6) LIMIT ? [["LIMIT", 1]]
↳ app/controllers/questions_controller.rb:86
(0.0ms) begin transaction
↳ app/controllers/questions_controller.rb:45
Question Destroy (0.4ms) DELETE FROM "questions" WHERE "questions"."id" = ? [["id", 3]]
↳ app/controllers/questions_controller.rb:45
(1.6ms) commit transaction
↳ app/controllers/questions_controller.rb:45
Redirected to http://localhost:3000/questions
Completed 302 Found in 7ms (ActiveRecord: 2.4ms)
I want to delete an object with ID =6, but delete an object with ID = 3
Action Destroy in controller:
def destroy
#question = Question.find_by(params[:id])
#question.destroy
flash[:success] = 'Вопрос успешно удалён!'
redirect_to questions_path
end
Link_to helper for delete object:
<%= link_to qest, class: 'btn btn-outline-danger', method: :delete, data: {confirm: "Хорошо подумал?"} do %>
You are using find_by without mentioning the column. When used without specifying column, find_by uses it as WHERE condition
Change it to Question.find_by(id: params[:id])(returns nil if matching record is not found) or Question.find(params[:id])(raises ActiveRecord::RecordNotFound error if record not found).
This is the clue.
Question Load (0.1ms) SELECT "questions".* FROM "questions" WHERE (6) LIMIT ? [["LIMIT", 1]]
↳ app/controllers/questions_controller.rb:86
This is generated from #question = Question.find_by(params[:id]). Note the WHERE (6). find_by takes either a single argument of raw SQL to use in the where clause, or a column and a value. You've only given it a single argument, so it's interpreted it as SQL and thus WHERE (6). This will be true for every column, so you get some random column, in this case 3, then you destroy it.
Instead you want:
#question = Question.find_by(id: params[:id])
Or better, use find.
#question = Question.find(params[:id])
And if you're just going to destroy it, use destroy on the class.
Question.destroy(params[:id])

Why doesn't projects/12 show all fields for that project?

IMPORTANT NOTE: The id does not matter, it is same in all cases.
I am only seeing the name field, not description, hours, etc even though these aren't null.
I have declared all standard routes through resources (with default format json), not individually.
I have even tried creating a projects/show.json.jbuilder file:
json.name #project.name
json.description #project.description
json.hours #project.hours
json.ownername #project.ownername
My projects/show method:
#project = Project.find(params[:id])
render :json => #project
FIRST EDIT:
I added logger.debug right before defining #project in my show method.
Now in my command prompt window for the local server, I am seeing:
Started GET "/projects/12" for 127.0.0.1 at 2015-02-25 16:36:45 -0500
ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations".* FROM "schema_migrations"
Processing by ProjectsController#show as HTML
Parameters: {"id"=>"12"}
Project Load (0.1ms) SELECT "projects".* FROM "projects" WHERE "projects"."id" = ? LIMIT 1 [["id", 12]]
#<Project:0x007f95477e72f8>
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 51]]
Completed 200 OK in 42ms (Views: 15.2ms | ActiveRecord: 0.9ms)
I am wondering why I am seeing the "User Load" part, since my Project model does not belong to a User object or have any relationship with it (though in the past it may have had before that relationship was removed). Also, I don't think I saw
#<Project:0x007f95477e72f8>
earlier.
I solved my problem this way.
Basically, projects/12.json currently works and not projects/12. Since I am more interested in obtaining the data client side, it is ok for me. I would need a projects/show.html.erb page that calls all the project data through view helper methods, for the HTML to work.
def show
#project = Project.find(params[:id])
respond_to do |format|
format.html
format.json
end
end
projects/12.json works because I have a projects/show.json.jbuilder file (as I shared in my original question post):
json.name #project.name
json.description #project.description
json.hours #project.hours
json.ownername #project.ownername

Even though I have a scoped nested route, my resources are not routing properly - Rails 3.1

This is my route:
scope ":username" do
resources :feedbacks
end
So when I go to mydomain.com/test/feedbacks/10 it shows the correct feedback with id=10 that belongs to username=test.
But, if I go to mydomain.com/test2/feedbacks/10 it shows me the same feedback with id=10, which does NOT belong to username=test2.
How do I restrict this from happening?
I am using the Vanity gem to give me the username in the URL, this is what that route looks like:
controller :vanities do
match ':vname' => :show, :via => :get, :constraints => {:vname => /[A-Za-z0-9\-\+\#]+/}
end
Edit 1:
That is to say, for clarity's sake, when I go to mydomain.com/test/feedbacks/10 and /test2/feedbacks/10, it shows me the same view for the same record (in which case, the latter version would be wrong because it should be telling me that no such record exists, but it's not. It is just displaying the correct record for test/feedbacks/10).
Edit 2:
Here are the logs of both requests:
The right request
Started GET "/test-3/feedbacks/7" for 127.0.0.1 at 2011-09-14 02:48:15 -0500
Processing by FeedbacksController#show as HTML
Parameters: {"username"=>"test-3", "id"=>"7"}
Feedback Load (0.5ms) SELECT "feedbacks".* FROM "feedbacks" WHERE "feedbacks"."id" = ? LIMIT 1 [["id", "7"]]
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 LIMIT 1
Rendered feedbacks/show.html.erb within layouts/application (36.2ms)
Completed 200 OK in 188ms (Views: 184.3ms | ActiveRecord: 1.8ms)
The wrong request
Started GET "/test2/feedbacks/7" for 127.0.0.1 at 2011-09-14 02:48:28 -0500
Processing by FeedbacksController#show as HTML
Parameters: {"username"=>"test2", "id"=>"7"}
Feedback Load (0.1ms) SELECT "feedbacks".* FROM "feedbacks" WHERE "feedbacks"."id" = ? LIMIT 1 [["id", "7"]]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 LIMIT 1
Rendered feedbacks/show.html.erb within layouts/application (37.6ms)
Completed 200 OK in 50ms (Views: 47.5ms | ActiveRecord: 1.2ms)
Your show action should look something like
def show
#user = User.find_by_username(params[:username])
if #user == current_user
...
render "show"
else
flash[:alert] = "Record doesn't exist"
redirect_to root_path
end
end
I took the liberty of adding in #Benoit's suggestion.

Ajax Delete links log out current_user

The title pretty much explains it. I'm having an odd situation where views that allow users to delete notifications using Ajax cause the current_user to be logged out. I don't even know where to begin debugging this...
Here's the controller
class NotificationsController < ApplicationController
def destroy
#notification = Notification.find(params[:id])
#notification.destroy
respond_to do |format|
format.js
end
end
end
This is the entire controller, nothing is abridged. The notifications are generated by the system, so the only action a user can take is to "dismiss" (ie. delete) them.
I also tried this using the newer respond_with syntax and had the same effect.
I'm using Devise, and Rails 3.0.9. Any idea what could be going on -- or suggestions on how to debug??
-- EDIT 1 --
Routes.rb
resources :notifications, :only => [:destroy]
Delete link
%span.delete= link_to( 'dismiss', notification_path(notification), :method => :delete, :remote => true )
-- EDIT 2 --
Well, I noticed something new in the logs -- see **** below.
Started DELETE "/notifications/10" for 127.0.0.1 at 2011-06-21 21:47:15 -0500
Processing by NotificationsController#destroy as JS
Parameters: {"id"=>"10"}
SQL (0.4ms) SELECT name
FROM sqlite_master
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
SQL (0.3ms) SELECT name
FROM sqlite_master
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
User Load (0.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
Slug Load (0.4ms) SELECT "slugs".* FROM "slugs" WHERE ("slugs".sluggable_id = 1 AND "slugs".sluggable_type = 'User') ORDER BY id DESC LIMIT 1
****AREL (0.3ms) UPDATE "users" SET "remember_token" = NULL, "remember_created_at" = NULL, "updated_at" = '2011-06-22 02:47:15.913839', "preferences" = '---
:email_notifications: ''true''
' WHERE "users"."id" = 1
Notification Load (0.2ms) SELECT "notifications".* FROM "notifications" WHERE "notifications"."id" = 10 LIMIT 1
User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
AREL (0.3ms) UPDATE "users" SET "notifications_count" = COALESCE("notifications_count", 0) - 1 WHERE "users"."id" = 1
AREL (0.1ms) DELETE FROM "notifications" WHERE "notifications"."id" = 10
Rendered notifications/destroy.js.erb (0.7ms)
Completed 200 OK in 6416ms (Views: 9.6ms | ActiveRecord: 4.1ms)
So, there it is, it looks like part of the users table is getting set to null, particularly the remember_token which I suspect is triggering Devise to end the session, or maybe this is done by Devise after the session is destroyed. But how do I track that down?
The only thing I can think of that causes notifications to interact with Users is there's a counter_cache on Users for notifications_count.
I appreciate thoughts and suggestions on how to debug!
-- EDIT 3 --
After digging with ruby-debug it looks like the issue is related to Devise and changes to the rails.js script. See:
https://github.com/plataformatec/devise/issues/913
https://github.com/ryanb/cancan/issues/280
I'm trying out some of the suggestions on those threads and will post if I find a solution.
I had a similar problem. Solution was as simple as adding
<%= csrf_meta_tag %>
to the layout.
It turns out this had to do with changes to the Rails jQuery UJS driver and Devise. I had updated Devise without updating jQuery UJS -- and Devise was expecting the CSRF token to be handled differently, so it was processing the ajax request as unauthorized which meant destroying the current user's session. Upgrading to the latest jQuery Rails driver fixed the problem.
Are you sure this controller and action are the ones that are triggered by the request? It sounds like the path you are DELETEing isnt right and you are hitting your sessions path instead.
Is it possible that the destroy notification path is redirecting to the session destroy path through JS?
Do you have destroy.js template in your notifications views? try adding one that is empty see if you get a different result.

Resources