I recently posted a question similar to this but I've narrowed down the problem and wanted to refine the question. Anyway, I have a blog with recipes (equivalent of posts or articles) and comments on those recipes. I've put in my application_controller.rb file the code for current_user:
def current_user
return unless session[:user_id]
#current_user = User.find_by_id(session[:user_id])
end
# Make current_user available in templates as a helper
helper_method :current_user
I tried to make it so that you had to be logged in to delete a comment on an article. That code is in my comments_controller.rb file:
def destroy
#recipe = current_user.recipes.find(params[:recipe_id])
#comment = #recipe.comments.find(params[:id])
#comment.destroy
redirect_to #recipe, notice: 'Comment Deleted'
end
I've narrowed it down to that first line of code within the destroy method. I believe that my application can't associate the recipe with the current_user and so can't save #recipe properly, so the #comment won't delete. Each recipe has a user_id parameterHere's the error, from the server console, when I try to delete a comment with a logged in user:
Started DELETE "/recipes/4/comments/4" for 127.0.0.1 at 2015-02-12 13:42:54 -0500
Processing by CommentsController#destroy as HTML
Parameters: {"authenticity_token"=>"+0pWfNOPJXLOzgUhA//q4ySh5rk01SlKmTRQx0qdDOrvkUOcIzF8GCb5jKwjsDlUvQsxxGTOOtJv6rPjn3jfoA==", "recipe_id"=>"4", "id"=>"4"}
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 6]]
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 6]]
Recipe Load (0.1ms) SELECT "recipes".* FROM "recipes" WHERE "recipes"."user_id" = ? AND "recipes"."id" = ? ORDER BY published_at DESC, title ASC LIMIT 1 [["user_id", 6], ["id", 4]]
Completed 404 Not Found in 50ms
ActiveRecord::RecordNotFound (Couldn't find Recipe with 'id'=4 [WHERE "recipes"."user_id" = ?]):
app/controllers/comments_controller.rb:15:in `destroy'
Anyone have any ideas?
NOTE: when I change the first line of code within the destroy method of my comments_controller to:
#recipe = Recipe.find(params[:recipe_id])
it works. I don't want that to be the code though bc then a non-logged in user can delete comments. AND, that revised code is the same code as a private method i put within my comments_controller:
private
def load_recipe
#recipe = Recipe.find(params[:recipe_id])
end
There is also a before_filter on that method in my comments_controller:
before_filter :load_recipe, :except => :destroy
before_filter :authenticate, :only => :destroy
Related
Here is the code I'm trying to use in my controller:
profiles_controller.rb:
class ProfilesController < ApplicationController
...
def update
respond_to do |format|
# assume valid data sent (I've already tested for this)
if #user.update(user_params)
# password_reset? check's parameter passed to action that a check box was
# checked (which enables/disables password/confirmation fields. If unchecked,
# fields are disabled and no password parameters are sent to this action.
# #user was set to current_user in a before_action already
# inspecting #user at this point returns the same thing as current_user here
sign_in(:user, #user) if password_reset?
# current_user is still set to #user and is valid
# after redirection current_user becomes nil
format.html {
redirect_to home_path, notice: 'Your profile was successfully updated.'
}
else
format.html { render :edit }
end
end
end
...
private
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
#user_params ||= params.require(:user).permit(:first_name, :last_name, :email, :phone, :password, :password_confirmation, :reset_password)
end
def password_reset?
#user_params["reset_password"] == "1"
end
end
application_controller.rb:
class ApplicationController < ActionController::Base
...
private
...
def require_user
logger.debug "IN REQUIRE_USER, CURRENT_USER IS: #{current_user.inspect}"
unless current_user
store_location
redirect_to new_user_session_url, notice: "That url doesn't exist."
return false
end
end
def require_admin
# this line will actually log a user in
#sign_in(:user, User.first) unless current_user
logger.debug "IN REQUIRE_ADMIN, CURRENT_USER IS: #{current_user.inspect}"
unless current_user && current_user.is_admin?
redirect_to(home_path, notice: "That url doesn't exist.") and return false
end
end
...
end
development.log:
Started PATCH "/profile" for 127.0.0.1 at 2019-05-28 10:38:45 -0700
Processing by ProfilesController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"....", "user"=>{....}, "commit"=>"Update Profile"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
↳ app/controllers/application_controller.rb:47
IN REQUIRE_USER, CURRENT_USER IS: #<User id: 1 ....>
(0.1ms) begin transaction
↳ app/controllers/profiles_controller.rb:16
User Exists (0.4ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER(?) AND "users"."id" != ? LIMIT ? [["email", "...."], ["id", 1], ["LIMIT", 1]]
↳ app/controllers/profiles_controller.rb:16
User Update (0.3ms) UPDATE "users" SET "encrypted_password" = ?, "updated_at" = ? WHERE "users"."id" = ? [["encrypted_password", "$2a$11...."], ["updated_at", "2019-05-28 17:38:45.346414"], ["id", 1]]
↳ app/controllers/profiles_controller.rb:16
(2.3ms) commit transaction
↳ app/controllers/profiles_controller.rb:16
PASSWORDS PASSED IN SO USER PASSWORD CHANGE OCCURRED
REDIRECTING TO HOME PATH
Redirected to http://localhost:3000/admin
Completed 302 Found in 121ms (ActiveRecord: 3.2ms)
Started GET "/admin" for 127.0.0.1 at 2019-05-28 10:38:45 -0700
Processing by Admin::PagesController#index as HTML
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
↳ app/controllers/application_controller.rb:65
IN REQUIRE_ADMIN, CURRENT_USER IS: nil
Redirected to http://localhost:3000/
Filter chain halted as :require_admin rendered or redirected
Completed 302 Found in 2ms (ActiveRecord: 0.2ms)
Started GET "/" for 127.0.0.1 at 2019-05-28 10:38:45 -0700
Processing by PagesController#index as HTML
Rendering pages/index.html.erb within layouts/application
Rendered pages/index.html.erb within layouts/application (0.7ms)
Rendered application/_navigation.html.erb (1.7ms)
Rendered application/_alert.html.erb (0.3ms)
Completed 200 OK in 1152ms (Views: 1151.2ms | ActiveRecord: 0.0ms)
I've searched around and seen by_pass: true being passed to sign_in but that doesn't help. I've also tried #current_user = #user once I've signed the user in (#current_user is the direct instance variable for the Devise controller btw) and that does not help either.
Any ideas?
Devise ignores signin if the user is already signed in, try:
if #user.saved_change_to_encrypted_password? # for rails 5+, for previous - .encrypted_password_changed?
sign_in #user, force: true
end
You can signin new session if the user is already signed in.
Devise said
# Sign in a user bypassing the warden callbacks and stores the user
# straight in session. This option is useful in cases the user is
# signed in, but we want to refresh the credentials in session.
Please use like below one.
bypass_sign_in(#user)
I have my form to save to my Stripe_account table. I recently nested the resources and now the form won't save to my database tables. I have it still working with the Stripe API and working there though.
What in my code is lacking?
User Model:
has_one :stripe_account
Stripe_account Model:
belongs_to :users
Stripe_account controller:
def new
#stripe_account = StripeAccount.new
#user = User.find(params[:user_id])
end
def create
#stripe_account = StripeAccount.new(stripe_account_params)
#user = User.find(params[:user_id])
acct = Stripe::Account.create({
.....
.....
#stripe_account.id = current_user.id
#stripe_account.acct_id = acct.id
respond_to do |format|
# #user = User.find(params[:id])
if #stripe_account.save
# current_user = #user
#user.stripe_account = acct.id
format.html { redirect_to new_bank_account_path, notice: 'Stripe account was successfully created.' }
format.json { render :show, status: :created, location: #stripe_account }
else
format.html { render :new }
format.json { render json: #stripe_account.errors, status: :unprocessable_entity }
end
end
end
View:
<%= form_for ([#user, #stripe_account]) do | f | %>
Routes:
resources :users do
resources :stripe_accounts
end
#added for testing
get 'stripe_' => "stripe_account#create"
get 'stripe_new' => "stripe_account#new"
Here's my routes maybe can help?: https://pastebin.com/RVWd2Qq9
Now even though I don't have the "bankaccount" controller or models set up correctly yet, shouldn't it be at least attempting to go there and saving the stripe_account? Just making sure that's not the issue. But it appears it's failing because a new form reloads.
The API is successfully going through as well and the accounts are appearing within stripe, just not my own database.
What in my programming is wrong?
Update to add cmd response:
Started POST "/users/2/stripe_accounts" for 127.0.0.1 at 2018-11-10 00:11:26 -0500
Processing by StripeAccountsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"nz1234567890iJuFwsm/Z4ylhE6zoGdWN6QCfWtDZTH1sxZu/WCdWMKBGkc4zoZ2dOgk9c8UDwRzgqdxrT/sA==", "stripe_account"=>{"account_type"=>"individual", "business_name"=>"", "business_tax_id"=>"", "first_name"=>"Dill", "last_name"=>"Pickles", "ssn_last_4"=>"1234", "dob_month"=>"3", "dob_day"=>"4", "dob_year"=>"1917", "address_line1"=>"198 berry avenue", "address_city"=>"san fran", "address_state"=>"CA", "address_postal"=>"90213", "tos"=>"1", "id"=>"2"}, "full_account"=>"{:value=>\"true\"}", "button"=>"", "user_id"=>"2"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 2], ["LIMIT", 1]]
↳ /home/bob/.rvm/gems/ruby-2.5.1/gems/activerecord-5.2.1/lib/active_record/log_subscriber.rb:98
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]]
↳ app/controllers/stripe_accounts_controller.rb:49
(0.1ms) begin transaction
↳ app/controllers/stripe_accounts_controller.rb:91
(0.1ms) rollback transaction
↳ app/controllers/stripe_accounts_controller.rb:91
Rendering stripe_accounts/new.html.erb within layouts/application
Rendered stripe_accounts/_account_form.html.erb (9.4ms)
Rendered stripe_accounts/new.html.erb within layouts/application (12.5ms)
Rendered layouts/_navbar.html.erb (1.9ms)
Rendered layouts/_footer.html.erb (0.4ms)
Completed 200 OK in 3202ms (Views: 190.0ms | ActiveRecord: 2.4ms)
Validation failed: User must exist
You can either use optional :true to resolve the error
#stipe_account.rb
belongs_to :user, optional: true
#^ should be singular
OR
Assign the user_id in the create action like so
#stripe_account.user_id = current_user.id #add this line
Update:
undefined method `user_id=' for StripeAccount:0x001234f4c58692ae8 Did
you mean? user="
The error is because you don't have user_id column in stripe_accounts table. Generate a migration that will do the job for you
rails g migration add_user_id_to_stripe_accounts user_id:integer
and do rails db:migrate
I'm creating a Rails 5.2 e-commerce application. I am using the active_record-acts_as gem to simulate multi-table inheritance that has a parent class named Product and multiple subclasses (Book, Clothing, Electronic...etc) that all act as a Product (they inherit all of Product's attributes and methods).
Each Product can only be created in the context of a Category, which corresponds to the names of Product's subclasses. For a visual, here is my current ProductsController...
class ProductsController < ApplicationController
before_action :set_category, only: [:new, :create]
before_action :set_product_type, only: [:new, :create]
before_action :set_product, only: [:show, :edit, :destroy]
def show
authorize #product
end
def new
#product = Product.new(actable: #product_type.new)
authorize #product
end
def create
#product = #product_type.new product_params
authorize #product
#product.category = #category
#product.user = current_user
if #product.save
redirect_to product_path #product.slug
else
render :new
end
end
def edit
#product = Product.friendly.find(params[:id])
authorize #product
#category = #product.category
set_product_type
end
def update
#product = Product.friendly.find(params[:id])
authorize #product
#category = #product.category
set_product_type
if #product.update product_params
redirect_to product_path #product.slug
else
render :edit
end
end
def destroy
authorize #product
#category = #product.category
if #product.destroy
redirect_to category_path(#category)
else
redirect_to request.referrer
end
end
private
def set_category
#category = Category.friendly.find(params[:category_id])
end
def set_product
# specific comes from active_record_acts-as gem
#product = Product.friendly.find(params[:id]).specific
end
def set_product_type
#product_type = #category.name.singularize.capitalize.constantize
end
def product_params
params.require(:product).permit(:name, :description, :price_cents, :main_image, actable_attributes: (#product_type.permitted_params))
end
end
Everything currently works. However, I had to add this to the product model per this SOF question, although, I modified it to use update instead of new, to correct my specific issue.
ACTABLE_TYPES = %w(Book Supply Electronic etc...)
def build_actable(params)
raise "Unknown actable_type: #{actable_type}" unless ACTABLE_TYPES.include?(actable_type)
self.actable.update(params)
end
If the build_actable method is not included, the create action works but update action does not. The error, without build_actable when I try to update a Product (subclass of Product) is...
Cannot build association actable. Are you trying to build a polymorphic one-to-one association?
Main Question
Although my current controller and build_actable method "works", every time I update a Product attribute, it updates updated_at three times...here is the log output...
Book Load (0.7ms) SELECT "books".* FROM "books" WHERE "books"."id" = $1 LIMIT $2 [["id", 13], ["LIMIT", 1]]
↳ app/controllers/products_controller.rb:45
Product Update (1.0ms) UPDATE "products" SET "name" = $1, "updated_at" = $2 WHERE "products"."id" = $3 [["name", "Where Angels Fear to Tread something else "], ["updated_at", "2018-07-26 03:28:30.414635"], ["id", 13]]
↳ app/models/product.rb:22
Product Update (0.7ms) UPDATE "products" SET "updated_at" = $1 WHERE "products"."id" = $2 [["updated_at", "2018-07-26 03:28:30.417622"], ["id", 13]]
↳ app/models/product.rb:22
Product Update (0.5ms) UPDATE "products" SET "updated_at" = $1 WHERE "products"."id" = $2 [["updated_at", "2018-07-26 03:28:30.420007"], ["id", 13]]
↳ app/models/product.rb:22
(5.0ms) COMMIT
My controller should certainly be refactored...but why is it updating updated_at 3 times???
Note: I've tried calling build_actable directly instead of update in the controller...but it does the same thing. I have also removed timestamps from Product's subclasses.
I feel like I'm missing something obvious....
I was able to correct the issue of updating timestamps twice by adding touch: false to the acts as association in Product's subclasses...
acts_as :product, touch: false
I'm using the Best In Place Gem to do inline edits on a table of Tasks that has a nested attribute for Storeorder, however when I try to edit a Storeorder attribute using the instructions provided in this post, I get a 204 No Content error thrown at me. I wonder if it has to do with the first transaction beginning before the 'Storeorder Load' happens? In all non-nested BIP updates, it does the UPDATE within the first "begin transaction" call, whereas here it's still loading the Storeorder. The parameters are 100% correct as far as I can tell. See code,
Started PUT "/tasks/3" for 104.200.151.54 at 2017-02-05 18:08:24 +0000
Processing by TasksController#update as JSON
Parameters: {"task"=>{"storeorder_attributes"=>{"id"=>"3", "activity"=>"Shipped"}}, "authenticity_token"=>"D2c3ddoIC220rkPE5i7U+EGiwSrdCq7s8vdFY8VEQTaTMqetuBo8SJX9+Wabl+Bh6A6d49Pt/Omp4E/nq/udQA==", "id"=>"3"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
Task Load (0.2ms) SELECT "tasks".* FROM "tasks" WHERE "tasks"."id" = ? LIMIT ? [["id", 3], ["LIMIT", 1]]
CACHE (0.0ms) SELECT "tasks".* FROM "tasks" WHERE "tasks"."id" = ? LIMIT ? [["id", 3], ["LIMIT", 1]]
(0.1ms) begin transaction
Storeorder Load (0.2ms) SELECT "storeorders".* FROM "storeorders" WHERE "storeorders"."task_id" = ? LIMIT ? [["task_id", 3], ["LIMIT", 1]]
(0.1ms) commit transaction
(0.1ms) begin transaction
(0.1ms) commit transaction
Completed 204 No Content in 10ms (ActiveRecord: 1.0ms)
tasks_controller.rb -->
class TasksController < ApplicationController
before_action :set_task, only: [:show, :edit, :update, :destroy]
def update
#task = Task.find(params[:id])
respond_to do |format|
if #task.update(task_params)
format.html { redirect_to #task, notice: 'Task was successfully updated.' }
format.json { respond_with_bip(#task) }
else
format.html { render :edit }
format.json { respond_with_bip(#task) }
end
end
end
private
def set_task
#task = Task.find(params[:id])
end
def task_params
params.require(:task).permit!
end
end
task.rb -->
class Task < ApplicationRecord
has_one :storeorder, :dependent => :destroy
accepts_nested_attributes_for :storeorder, :reject_if => lambda { |a| a[:store_id].blank? }, :allow_destroy => true
end
storeorder.rb -->
class Storeorder < ApplicationRecord
belongs_to :task
end
dashboard.html.erb -->
<td><%= best_in_place task.storeorder, :activity,
url: task_path(task.id),
param: "task[storeorder_attributes][id]=#{task.storeorder.id}&task[storeorder_attributes]",
as: :select,
collection: [["Pending Shipment", "Pending Shipment"], ["Shipped", "Shipped"], ["Cancelled", "Cancelled"], ["Pending Further Action", "Pending Further Action"]], %>
</td>
inner HTML code -->
<span
data-bip-type="select"
data-bip-attribute="activity"
data-bip-collection="[["Pending Shipment","Pending Shipment"],["Shipped","Shipped"],["Cancelled","Cancelled"],["Pending Further Action","Pending Further Action"]]"
data-bip-inner-class="form-control"
data-bip-object="task[storeorder_attributes][id]=3&task[storeorder_attributes]"
data-bip-original-content="Pending Shipment"
data-bip-skip-blur="false"
data-bip-url="/tasks/3"
data-bip-value="Shipped"
class="best_in_place form-control"
id="best_in_place_storeorder_3_activity">
Shipped
</span>
I can't see what I could possibly be missing that causes this error. It's imperative that I'm allowed to do inline edits to keep the workflow consistent, otherwise I'm open to alternative suggestions since I know BIP doesn't have nested attribute editing within their scope by default.
:reject_if => lambda { |a| a[:store_id].blank? }
Don't see any store_id being passed in params.
I want to add a message when user tries to sign in and it's not confirmed, I want to display this message in notice section, basically devise needs to provide this message to us but I don't see any message in this cases. So I decided to add it manually from sessions controller here is my code:
class SessionsController < Devise::SessionsController
def new
super
end
def create
user = User.find_by_email(params[:user][:email])
self.resource = warden.authenticate!(auth_options)
set_flash_message(:notice, :signed_in) if is_flashing_format?
sign_in(resource_name, resource)
if user.confirmed_at.nil?
flash[:notice] = "my message here"
end
yield resource if block_given?
respond_with resource, location: after_sign_in_path_for(resource)
end
end
the problem is flash[:notice] is empty after action is executed, in console I have
Started POST "/users/sign_in" for 127.0.0.1 at 2014-11-18 15:07:21 +0200
Processing by SessionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"xC86tz4kZjcSMqXOL/+qpwlh5VlSbnsvLj93N5jb3NI=", "user"=>{"email"=>"pers.maki.5#gmail.com", "password"=>"[FILTERED]"}, "commit"=>"Sign in"}
(0.2ms) SELECT COUNT(*) FROM "landing_page_reports"
LandingPageReport Load (0.2ms) SELECT "landing_page_reports".* FROM "landing_page_reports" ORDER BY "landing_page_reports"."id" DESC LIMIT 1
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."email" = 'pers.maki.5#gmail.com' LIMIT 1
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."email" = 'pers.maki.5#gmail.com' LIMIT 1
(0.1ms) begin transaction
(0.2ms) commit transaction
Completed 401 Unauthorized in 193ms
how can I display this message?
More simple way to do what are asking about is to add before_filter :confirmation_notice in you application_controller and check whether current_user.confirmed? or not.
ex ::
before_filter :confirmation_notice
def confirmation_notice
flash[:notice] = "my message here" unless current_user.confirmed?
end
Do not forget to configure your views to show this flash notice.
This to learn how to configure your views.