I am trying compile a function with user id, but not working out. Tried different ways but getting nil as response in my production logs.
Any help is welcome
def function(user)
attachments['example.pdf'] = File.read("public/#{#user.id}_file.pdf")
#user = user
mail :subject => 'example', to: user.email, from: 'invoice#domain.com', track_opens: true
end
Log:
D, [2019-07-08T10:51:56.838759 #64733] DEBUG -- :
TestMailer#send_sub_month: processed outbound mail in 1.1ms I,
[2019-07-08T10:51:56.839003 #64733] INFO -- : Completed 500 Internal
Server Error in 5ms (ActiveRecord: 0.4ms) F,
[2019-07-08T10:51:56.839615 #64733] FATAL -- : F,
[2019-07-08T10:51:56.839671 #64733] FATAL -- : NoMethodError
(undefined method 'id' for nil:NilClass): F,
[2019-07-08T10:51:56.839710 #64733] FATAL -- : F,
[2019-07-08T10:51:56.839750 #64733] FATAL -- :
app/mailers/test_mailer.rb:90:in `send_sub_month'
The logs say that you are trying to access the id attribute of an empty object.
NoMethodError (undefined method id' for nil:NilClass)
You have a string where the user is used is higher than the string where the user is defined
Try this:
def function(user)
#user = user
attachments['example.pdf'] = File.read("public/#{#user.id}_file.pdf")
mail :subject => 'example', to: user.email, from: 'invoice#domain.com', track_opens: true
end
Updated.
If you pass a user as an argument to a function, then it makes no sense to create a variable for it.
def function(user)
attachments['example.pdf'] = File.read("public/#{user.id}_file.pdf")
mail :subject => 'example', to: user.email, from: 'invoice#domain.com', track_opens: true
end
Related
Following the hartle tutorial here: https://www.learnenough.com/action-cable-tutorial#sec-upgrading_to_action_cable
When I get to Step 4, adding ActionCable the chat messages are not transmitted and I get the error:
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" IS NULL LIMIT ? [["LIMIT", 1]]
An unauthorized connection attempt was rejected
here are the relevant files:
room_channel.rb:
class RoomChannel < ApplicationCable::Channel
def subscribed
stream_from "room_channel"
end
def unsubscribed
# Any cleanup needed when channel is unsubscribed
end
end
messages controller:
class MessagesController < ApplicationController
before_action :logged_in_user
before_action :get_messages
def index
end
def create
message = current_user.messages.build(message_params)
if message.save
ActionCable.server.broadcast 'room_channel',
message: render_message(message)
message.mentions.each do |mention|
ActionCable.server.broadcast "room_channel_user_# {mention.id}",
mention: true
end
end
end
private
def get_messages
#messages = Message.for_display
#message = current_user.messages.build
end
def message_params
params.require(:message).permit(:content)
end
def render_message(message)
render(partial: 'message', locals: { message: message })
end
end
room.coffee:
App.room = App.cable.subscriptions.create "RoomChannel",
connected: ->
# Called when the subscription is ready for use on the server
disconnected: ->
# Called when the subscription has been terminated by the server
received: (data) ->
# Called when there's incoming data on the websocket for this channel
alert data.content
routes.rb:
Rails.application.routes.draw do
root 'messages#index'
resources :users
resources :messages
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
mount ActionCable.server, at: '/cable'
end
The reference branch works fine on my machine, but I can't get my tutorial branch to use AC.
Update:
Skipping down to Section 5 of the tutorial, I added connection.rb, which had been blank in the tutorial's beginning repo as follows:
connection.rb:
module ApplicationCable
class Connection < ActionCable::Connection::Base
include SessionsHelper
identified_by :message_user
def connect
self.message_user = find_verified_user
end
private
def find_verified_user
if logged_in?
current_user
else
reject_unauthorized_connection
end
end
end
end
And broadcasting seems to work in one direction. I have two tabs open. but only one works to broadcast messages. In the other, the console shows this error:
Error: Existing connection must be closed before opening action_cable.self-17ebe4af84895fa064a951f57476799066237d7bb5dc4dc351a8b01cca19cce9.js:231:19
Connection.prototype.open
http://localhost:3000/assets/action_cable.self-17ebe4af84895fa064a951f57476799066237d7bb5dc4dc351a8b01cca19cce9.js:231:19
bind/<
http://localhost:3000/assets/action_cable.self-17ebe4af84895fa064a951f57476799066237d7bb5dc4dc351a8b01cca19cce9.js:201:60
In the logs, with the above connection.rb, the search for null user is gone, showing this:
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Registered connection (Z2lkOi8vY2hhdC1hcHAvVXNlci8x)
RoomChannel is transmitting the subscription confirmation
RoomChannel is streaming from room_channel
Started GET "/cable" for ::1 at 2018-12-29 08:04:31 -0500
Started GET "/cable/" [WebSocket] for ::1 at 2018-12-29 08:04:31 -0500
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: keep-alive, Upgrade, HTTP_UPGRADE: websocket)
I'm having an issue where my integration tests do not seem to find the log_in_as method from my test_helper.rb
I have been following Michael Hart's Rails tutorial, so I was hoping not to massively refactor my code to try and get this to work. I would like to continue on through the book without having to exclude the tests, since it is pretty test heavy afterall.
Error:
UsersLoginTest#test_login_with_remembering:
NoMethodError: undefined method `log_in_as' for #<UsersLoginTest:0x00000005b18460>
test/integration/users_login_test.rb:43:in `block in <class:UsersLoginTest>'
User_login_test.rb:
require 'test_helper.rb'
class UsersLoginTest < ActionDispatch::IntegrationTest
.
.
.
test "login with remembering" do
log_in_as(#user, remember_me: '1')
assert_not_empty cookies['remember_token']
end
test "login without remembering" do
# Log in to set the cookie.
log_in_as(#user, remember_me: '1')
# Log in again and verify that the cookie is deleted.
log_in_as(#user, remember_me: '0')
assert_empty cookies['remember_token']
end
end
test_helper.rb:
ENV['RAILS_ENV'] ||= 'test'
class ActiveSupport::TestCase
fixtures :all
# Returns true if a test user is logged in.
def is_logged_in?
!session[:user_id].nil?
end
# Log in as a particular user.
def log_in_as(user)
session[:user_id] = user.id
end
end
class ActionDispatch::IntegrationTest
# Log in as a particular user.
def log_in_as(user, password: 'password', remember_me: '1')
post login_path, params: { session: { email: user.email,
password: password,
remember_me: remember_me } }
end
end
I had this same issue. There are two problems I had to fix:
Make sure there is only one test_helper.rb file, and
test_helper.rb is in the right folder
Hope this helps!
I am getting this error and using Rails 5.
NoMethodError (undefined method permit' for #<Array:0x007f51cf4dc948>
app/controllers/traumas_controller.rb:99:intrauma_params'
app/controllers/traumas_controller.rb:25:in `create_multiple'
Controller params are as below.
Started POST "/traumas/create_multiple" for 127.0.0.1 at 2016-10-04
20:09:36 +0530 Processing by TraumasController#create_multiple as JS
Parameters: {"utf8"=>"✓", "fields"=>[{"contusions"=>"1", "burns"=>"",
"at_scene"=>"At Scene", "emergency_detail_id"=>"96",
"trauma_region"=>"Head-Back"}], "commit"=>"Submit"}
I am trying to create record as below in controller:
def create_multiple
trauma_params
params[:fields].each do |values|
u = Trauma.create(values)
end
end
def trauma_params
params.require(:fields).permit(:fields => [])
end
Please help me to resolve this issue.
Thanks in advance.
Kiran.
Parameters:
{"fields"=>[{"contusions"=>"1", "burns"=>"", "at_scene"=>"At Scene", "emergency_detail_id"=>"96", "trauma_region"=>"Head-Back"}]}
Safelist array of objects, with the "fields" attribute required:
def trauma_params
params.permit(fields: [
:contusions,
:burns,
:at_scene,
:emergency_detail_id,
:trauma_region
])
.require(:fields)
end
Source: https://edgeguides.rubyonrails.org/action_controller_overview.html#nested-parameters
I resolved it by referring this (https://github.com/rails/strong_parameters/issues/140) github issue.
EDIT
For parameters like the following (which are in Array):
Parameters: {"fields"=>[{"contusions"=>"1", "burns"=>"",
"at_scene"=>"At Scene", "emergency_detail_id"=>"96",
"trauma_region"=>"Head-Back"}], "commit"=>"Submit"}
We can do:
def trauma_params
params.require(:fields).map do |p|
ActionController::Parameters.new(p).permit(
:contusions,
:burns,
:at_scene,
:emergency_detail_id,
:trauma_region
)
end
end
With the migration from Rails 2 to Rails 3 validation errors were moved from ActiveRecord::Error to ActiveModel::Errors.
In rails 2 the validation error had a type and a message (among other things) and you could check the type of the validation error by doing something like the following:
rescue ActiveRecord::RecordInvalid => e
e.record.errors.each do |attr, error|
if error.type == :foo
do_something
end
end
end
But with Rails 3 it seems everything but the invalid attribute and message has been lost. As a result the only way to determine the type is to compare the error message:
rescue ActiveRecord::RecordInvalid => e
e.record.errors.each do |attr, error|
if error == "foobar"
do_something
end
end
end
Which is not at all ideal (eg. what if you have several validations which use the same message?).
Question:
Is there a better way in rails 3.0 to determine the type of validation error?
Check for added? on ActiveModel::Errors:
https://github.com/rails/rails/blob/master/activemodel/lib/active_model/errors.rb#L331
That allows you to do this:
record.errors.added?(:field, :error)
I needed it not only for test purposes, but also for API. I've ended up with monkey patch:
module CoreExt
module ActiveModel
module Errors
# When validation on model fails, ActiveModel sets only human readable
# messages. This does not allow programmatically identify which
# validation rule exactly was violated.
#
# This module patches {ActiveModel::Errors} to have +details+ property,
# that keeps name of violated validators.
#
# #example
# customer.valid? # => false
# customer.errors.messages # => { email: ["must be present"] }
# customer.errors.details # => { email: { blank: ["must be present"] } }
module Details
extend ActiveSupport::Concern
included do
if instance_methods.include?(:details)
fail("Can't monkey patch. ActiveModel::Errors already has method #details")
end
def details
#__details ||= Hash.new do |attr_hash, attr_key|
attr_hash[attr_key] = Hash.new { |h, k| h[k] = [] }
end
end
def add_with_details(attribute, message = nil, options = {})
error_type = message.is_a?(Symbol) ? message : :invalid
normalized_message = normalize_message(attribute, message, options)
details[attribute][error_type] << normalized_message
add_without_details(attribute, message, options)
end
alias_method_chain :add, :details
def clear_with_details
details.clear
clear_without_details
end
alias_method_chain :clear, :details
end
end
end
end
end
# Apply monkey patches
::ActiveModel::Errors.send(:include, ::CoreExt::ActiveModel::Errors::Details)
I have a pretty standard authenticate method
private
def authenticate_user
#current_user = User.find_by_authentication_token(params[:token])
unless #current_user
error = { :error => "Invalid token." }
respond_with(error, :status => 401 )
end
end
I am calling the API to ensure the authenticate fails.
I get an error stating
ArgumentError (Nil location provided. Can't build URI.):
app/controllers/api/v1/base_controller.rb:13:in `authenticate_user'
What am I doing wrong?
By the specific flavor of your error, I am guessing that "authenticate_user" is called as part of a "create" action.
If that is the case, I believe the answer I provided here will help you as well.
Assuming, however, that this is part of creating an authenticated session, meaning there is no actual location for the newly created "resource", I would supply nil for the response location, as in:
...
respond_with(error, :status => 401, :location => nil)
...
That will make more sense once you have a look at the linked answer. If it still doesn't make sense, I'll be happy to clarify.
I changed respond_with to render and it worked:
render json: { success: false, message: "an error" }, status: 500