I am getting a beautiful error :
failed with NoMethodError: You have a nil object when you didn't expect it!
You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.[] - 3 failed attempts
My Controller:
CardSignup.all.each do |user|
Delayed::Job.enqueue MassEmail.new(user, params[:subject], params[:editor1])
end
mass_email.rb
class MassEmail < Struct.new(:user, :subject, :message)
def perform
Notifier.deliver_email_blast(user, subject, message)
end
end
_form.html.haml
- form_tag admin_email_blast_path do
Subject
%br
= text_field_tag 'subject'
%br
Body
%br
= text_area_tag 'message', '', :name => 'editor1'
%br
= submit_tag 'Send Email', :class => 'button'
:plain
<script type="text/javascript">
CKEDITOR.replace( 'editor1' );
</script>
The problem is because i'm not passing the varis right.. how do I do this proper?
note: It was working perfectly before i implemented delayed_jobs with params[:subject], and params[:editor1], so I have to retain those somehow.
I tried this without Delayed_Jobs, and the MassEmail.new doesn't even leave a backtrace in my log.
I also tried this in my console, and it froze.
There's got to be something wrong with the mass_email.rb or the call in def perform
This is definitively wrong, you gave two parameters the same name:
class MassEmail < Struct.new(:user, :params, :params)
How does the perform method now which param you're referring to?
You can try something like this
class MassEmail < Struct.new(:user, :subject, :editor1)
def perform
Notifier.deliver_email_blast(user, subject, editor1)
end
end
Kudos to JigFox for getting me to write the params right.
And I'm not entirely sure why this works, but I moved the loop into the MassEmail.new function.
Delayed::Job.enqueue MassEmail.new(params[:subject], params[:editor1])
class MassEmail < Struct.new(:subject, :editor1)
def perform
CardSignup.all.each do |user|
Notifier.deliver_email_blast(user, subject, editor1)
end
end
end
Related
I'm stuck on this... Asked a few questions already, but can't get my head around this.
I have a form for adding bibliography (model Biblio) that has a simple validation field on title of the bibliography.
Validation always fails, even when valid data is added.
MODEL
class Biblio < ApplicationRecord
# validates_presence_of :auteurs => there's a nested form too but
# I commented it out in order to isolate the problem
accepts_nested_attributes_for :auteurs
validates :titre, presence: true
CONTROLLER
(full text and I didn't translate in order to avoid typos)
def new
#biblio = Biblio.new(params_biblio)
#biblio.auteurs.build
end
def nouveau
# this method renders 'nouveau.html.erb',
# that contains the form allowing the addition of bibliography
#biblio = Biblio.new
if params[:id] # id is an optional parameter
#auteur = Auteur.find(params[:id])
#idauteur = #auteur.id
end
end
def ajouter
# is the method that treats the post form that was sent
#biblio = Biblio.new
if #biblio.save
# the 4 following lines are irrelevant here as they only add the
# second and subsequent authors to the join table.
# No validation and works fine.
b = auteurs_devises(params[:biblio][:auteurs])
aut = b.map do |var|
lett = Auteur.find(var)
lett.biblios << #biblio
end
redirect_to voir_biblio_url(Biblio.last)
else
if params[:id]
#auteur = Auteur.find(params[:id])
#idauteur = #auteur.id
end
render 'nouveau'
end
end
THE VIEW:
<%= form_for :biblio, url: administration_ajoute_biblio_url do |f| %>
<%= f.fields_for :auteurs do |aut| %>
<%= aut.label t('auteur') %>
<%= aut.text_field :nom , :name =>"biblio[auteurs][nom]", data: {autocomplete_source: auteurs_enum_path} %>
<% end %>
<%= f.label t('titre').capitalize %>
<%= f.text_field :titre %>
These are the params that are sent to the method nouveau:
Started POST "/administration/biblios/nouveau" for ::1 at 2017-02-07 21:28:28 +0100
Processing by Administration::BibliosController#ajouter as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"+354h4M0Tg+BX21XAuQ6YMKS0BGQ8UjET8paKjkGCBsS1up1lB131KsoaCy563X4juDz0EJy46WgXbHcu51Kgw==", "biblio"=>{"auteurs"=>{"nom"=>"Godding"}, "titre"=>"Test Tuesday Evening", "soustitre"=>"", "recueil"=>"", "editeur"=>"", "annee"=>"", "isbn"=>"", "genre"=>"source", "revue_id"=>"", "revue_no"=>"", "revue_page"=>"", "lieu"=>"", "commentaire"=>""}, "commit"=>"Enregistrer"}
(0.2ms) BEGIN
(0.1ms) ROLLBACK
Rendering administration/biblios/nouveau.html.erb within layouts/messources
CONTROLLER AGAIN
def params_biblio
params.require(:biblio).permit(
:titre,
:soustitre,
:editeur,
:isbn,
:recueil,
:genre,
:revue_id,
:revue_no,
:revue_page,
:annee,
:lieu,
:commentaire,
auteurs: [:nom] )
end
For the sake of completeness, here's my routes.rb:
# ADMINISTRATION => BIBLIOGRAPHIE
get 'biblios/nouveau(/:id)' => 'biblios#nouveau', as: 'nouvelle_biblio'
post 'biblios/nouveau(/:id)' => 'biblios#ajouter', as: 'ajoute_biblio'
delete 'biblios/supprime/:id' => 'biblios#supprime', as: 'supprime_biblio'
get 'biblios/maj/:id' => 'biblios#cherche_maj', as: 'maj_biblio'
patch 'biblios/maj/:id' => 'biblios#maj', as: 'patch_maj_biblio'
I must be blind. I'm doing something wrong... I put a title to this bibliography ('Test Tuesday Evening'), this is the only field on which I left a validation, and despite this, validation always fails.
I have a view that calls a complaint form. It also happens to have a partial on the same page.
If I create a new complaint the validation works as intended. However, if I delete the contents of a validated field during an update and try to update/save, I get a crash/error but I am not getting any validation errors.
class Complaint < ActiveRecord::Base
belongs_to :customer, :class_name => 'Customer', :foreign_key => 'customer_id'
has_many :attachments, :dependent => :destroy
accepts_nested_attributes_for :attachments
has_many :document_histories #, :dependent => destroy
accepts_nested_attributes_for :document_histories
# has_one :user
has_many :users, :through => :document_histories
validate :resolution_must_be_in_the_future
validates_presence_of :status
validates_presence_of :sales_order
validates_presence_of :product_name
validates_presence_of :coater_roll_number
validates_presence_of :coater_work_order
validates_presence_of :slitter_disposition
validates_presence_of :length
validates_presence_of :measure
validates_presence_of :disposition
validates_presence_of :reason_for_complaint
validates_presence_of :customer
after_initialize :init
def init
if self.new_record? && self.status.nil? # see if it's a new record and if it is nill
self.status = 'New' # Set status - NOTE - in this case we used a dropbox collection so the setting should be something in the dropbox .
end
end
def resolution_must_be_in_the_future
errors.add(:resolution_date, "must be in the future") if
!requested_resolution_date.blank? && requested_resolution_date < Date.today && self.new_record?
end
end
Here are two of the fields in my complaints form. There are, of course, more fields.
<div class="field">
<strong><%= f.label :slitter_disposition %></strong><br>
<%= f.text_area :slitter_disposition, :rows => 10, :cols => 120 %>
</div>
<div class="field">
<strong><%= f.label :reason_for_complaint %></strong><br>
<%= f.text_area :reason_for_complaint, :rows => 5, :cols => 120 %>
</div>
If I delete the contents of any validated field while doing an update, I get an error of the following. In this case
NoMethodError in Complaints#update
Showing C:/Users/cmendla/RubymineProjects/internal_complaints/app/views/complaints/_form.html.erb where line #41 raised:
undefined method `name' for nil:NilClass
Trace of template inclusion: app/views/complaints/edit.html.erb
Rails.root: C:/Users/cmendla/RubymineProjects/internal_complaints
Application Trace | Framework Trace | Full Trace
app/views/complaints/_form.html.erb:41:in `block in _app_views_complaints__form_html_erb__591273067_68586864'
app/views/complaints/_form.html.erb:2:in `_app_views_complaints__form_html_erb__591273067_68586864'
app/views/complaints/edit.html.erb:89:in `_app_views_complaints_edit_html_erb__1060012553_73607220'
app/controllers/complaints_controller.rb:177:in `block (2 levels) in update'
app/controllers/complaints_controller.rb:160:in `update'
Request
Parameters:
{... removed irrelevent parameters
"reason_for_complaint"=>"",
My log file shows..
Rendered complaints/_form.html.erb (6.0ms)
Rendered complaints/edit.html.erb within layouts/application (22.0ms)
Completed 500 Internal Server Error in 35ms (ActiveRecord: 0.0ms)
ActionView::Template::Error (undefined method `name' for nil:NilClass):
40: -->
41:
42: <% if action_name != "new" && action_name != "create" then %>
43: <%= #user.name %>
44: <% else %>
45: <%= #current_user.name %>
46: <%= f.hidden_field(:user_id, :value => #current_user.id) %>
app/views/complaints/_form.html.erb:43:in `block in _app_views_complaints__form_html_erb__591273067_73900308'
app/views/complaints/_form.html.erb:2:in `_app_views_complaints__form_html_erb__591273067_73900308'
app/views/complaints/edit.html.erb:89:in `_app_views_complaints_edit_html_erb__1060012553_73607220'
app/controllers/complaints_controller.rb:177:in `block (2 levels) in update'
app/controllers/complaints_controller.rb:160:in `update'
No matter what field I leave blank, the error will always point to the same line as above. How can I ensure that the Rails validation works when I am doing an update?
-------------- Edit
If I remark out the validation for the field that is empty, then the update process without error. i.e if I remark out the line
# validates_presence_of :reason_for_complaint
then the form will process and the field will be blank in the table. The problem is that the validations are needed
------------------------ Edit 2
Here is the code where I'm getting the error. The code is not supposed to execute if it is a new complaint. It does not execute when there is an update with no validation errors. It appears that validation errors are causing the form to think it is new/create not edit/update.
<td>
<% if action_name != "new" && action_name != "create" then %>
<% $document_assign = #complaint.id %>
<% $sent_by_name = $current_user_name %>
<% $sent_by_login = #user.login %>
<% end %>
</td>
Seems like there are a couple of potential issues here, and without more code, it's hard to tell how the validation plays into it.
Let's first look at your server log. What it seems to be telling us is this: Your code is trying to call .name on nil -- which is no good.
This line, is the line it is borking on:
app/views/complaints/_form.html.erb:43:in block in _app_views_complaints__form_html_erb__591273067_73900308'
If we take a look at line 43 in your template code, it looks like you are trying to call .name on #user. OK, so that means, #user is nil at that point. Weird. Why would that be?
So, your first order of business is determining why would #user be nil at that point? Have you had a chance to step through your controller code and assure yourself that you are setting the #user variable before you send it out to the View?
#queserasera got me pointed in the correct direction. It appears that in the event of a validation failure, I need to set some variables/parameters that were in the edit controller in the create controller also. One of those happened to be #user.
I added the following to def user.
#users = User.uniq.pluck(:name)
#complaint = Complaint.find(params[:id])
#user = User.find(#complaint.user_id) # this points the complaint to the appropriate user record.
#existing_sent_to = DocumentHistory.where(:complaint_id => $document_assign)
$existing_sent_to = DocumentHistory.where(:complaint_id => $document_assign)
#attachments = #complaint.attachments
#user = User.find(#complaint.user_id) # this points the complaint to the appropriate user record.
# Grab the current complaint id, put it in $current_record_id. Then use that in the where clause.
# to show the document histories for the current record
$current_record_id = #complaint.id
$document_histories = DocumentHistory.where(["complaint_id like ?", "%#{$current_record_id}%"])
That seems to have resolved the issue. I still need to test this but I think it is working ok. I am no longer getting the error screen on a failed validation. I am simply getting the edit form with the rails validation messages.
I've seen many similar questions, and looked at the answers, but nothing seems to be helping me and I've been working on this for a while now. The error is 'Can't convert symbol into integer'. My goal is to be able to create multiple sub_groups for each race. I'm just starting with trying to create one for the time being. Here's the relevant code...
** UPDATE **
VIEW
<%= simple_form_for(#race, :url => form_path, :method => form_method, :html => { :class =>
'form-horizontal form-compressed' }) do |f| %>
<fieldset>
<%= f.simple_fields_for :sub_groups do |g| %>
<%= g.input :name, requred: false %>
<%= g.collection_radio_buttons :discount_type,
[['dollars', '$'], ['percent', '%']], :first, :last %>
<%= g.input :discount_amount, :as => :integer, required: false %>
<% end %>
<hr/>
** RACE MODEL**
class Race < ActiveRecord::Base
has_many :sub_groups
accepts_nested_attributes_for :sub_groups
attr_accessible :sub_groups_attributes
** SUB_GROUP MODEL **
class SubGroup < ActiveRecord::Base
belongs_to :race
has_many :race_users
attr_accessible :discount_amount, :discount_type, :display_results, :name
end
PARAMS
after my code update...
Parameters: {"utf8"=>"✓",
"authenticity_token"=>"VihBL4TDT/Lte4YBji/4fp4XvOri1UgUZ8B33wQuCko=", "race"=>
{"sub_group"=>{"name"=>"dfd", "discount_type"=>"dollars", "discount_amount"=>"2"}},
"commit"=>"Next", "wizard"=>"2", "id"=>"13-test5"}
CONTROLLER
class RacesController < ApplicationController
def new
#race = Race.new
#sub_groups = #race.sub_groups.build
#wizard_step = -1
#wizard_step_name = Race.wizard_step_name_from_id #wizard_step
#wizard_mode = true
render :layout => "race_wizard"
end
def update
#race = Race.find params[:id]
#wizard_step = params[:wizard].to_i + 1
#race.wizard_step = #wizard_step
#race.update_attributes(params[:race])
end
So I took advice from answer 1, and switched to using :sub_groups in the view. Now I have a new problem, which is the sub-group fields don't show up at all, despite the fact that I built a sub_groups thing in the #new method.
I'm really stumped on how I can make this happen. This is driving me bonkers. Any help is much appreciated. Thanks!
The way fields_for works is that if you supply a symbol it checks whether your model respond to {given_symbol}_attributes=. If it does the name of sub-fields is {given symbol}_attributes, otherwise just {given_symbol}.
What you need is to add accepts_nested_attributes_for :sub_groups to your Race model. This methods will create a default setter sub_groups_attributes=, which will make fields_for :sub_groups to generate fields with name sub_groups_attributes.
You can also write your own sub_groups_attributes= method, but you need to be sure you know what you're doing there as it might be a little tricky to debug.
Note, that fields_to :sub_groups won't display fields if there are no sub_group associated with given object - you will need to build one in your controller first.
I get
ActiveRecord::RecordNotFound: Couldn't find Client with ID=3 for Order with ID=
when trying to submit an Order form for an existing client. This happens through the form or the console by typing:
Order.new(:client_attributes => { :id => 3 })
payment_form.html.erb:
<%= semantic_form_for #order, :url => checkout_purchase_url(:secure => true) do |f| %>
<%= f.inputs "Personal Information" do %>
<%= f.semantic_fields_for :client do |ff| %>
<%= ff.input :first_name %>
<%= ff.input :last_name %>
<!-- looks like semantic_fields_for auto-inserts a hidden field for client ID -->
<% end %>
<% end %>
<% end %>
Order.rb:
class Order < ActiveRecord::Base
belongs_to :client
accepts_nested_attributes_for :client, :reject_if => :check_client
def check_client(client_attr)
if _client = Client.find(client_attr['id'])
self.client = _client
return true
else
return false
end
end
end
The reject_if idea came from here but I logged the method and it's not even being called! It doesn't matter what its name is!
Note: Feb 2020
Since I'm starting to get downvotes on this 8 years later, adding this note. While this was the original solution I went with 8 years ago, a better one has been proposed by MatayoshiMariano (5 years after my OP).
My Original Fix
Fixed the issue by overloading the client_attributes= method, as described here:
def client_attributes=(client_attrs)
self.client = Client.find_or_initialize_by_id(client_attrs.delete(:id))
self.client.attributes = client_attrs
end
If you only want a new Order with an existing client, without modifying the client, you need to assign the id.
Order.new(client_id: 3)
This is another way to do this without overloading the client_attributes= method and cleanest
The new Order now has the client with ID 3
If you also want to update ant client's attributes you must add the client_attributes, for example:
Order.new(client_id: 3, client_attributes: { id: 3, last_order_at: Time.current })
See https://github.com/rails/rails/issues/7256 from 2012.
If you have has_many relationship, this will work. Tested on Rails 6.0.2
def clients_attributes =(attributes)
# Get IDs for any clients that already exist.
client_ids = attributes.values.map { |a| a[:id] }.compact
# Now find them all and move them to this section.
clients << Client.find(client_ids)
# Update them with standard `accepts_nested_attributes_for` behaviour.
super attributes
end
Had the same error creating a new Thing for existing model with has_many and belongs_to relations.
Fixed it by adding a hidden field for the id of the existing model, for instance User, to the form.
= form.input :user_id, as: :hidden
Then new Thing was created without the error.
I'm trying to create a private messaging system for my website, and I am currently working on message replies. I've run into an ActiveRecord::AssociationTypeMismatch problem however. This is the error message:
ActiveRecord::AssociationTypeMismatch in RepliesController#create
Message(#58297820) expected, got String(#1635350)
I've been trying to figure out what the problem is for awhile now with no luck.
Below you will find my code for my migration, model, view, and controller.
Migration
def self.up
create_table :replies do |t|
t.integer :message_id, :null => false
t.integer :sender_id, :null => false
t.text :message, :null => false
t.timestamps
end
end
Model
class Reply < ActiveRecord::Base
belongs_to :message
validates_presence_of :message
cattr_reader :per_page
##per_page = 10
end
View
<% form_for(#reply) do |f| %>
<table>
<tr>
<td><%= f.text_area :message %></td>
</tr>
<%= f.hidden_field :message_id, :value => #message.id %>
<tr>
<td><%= f.submit 'Reply', :id => 'replySubmit' %></td>
</tr>
</table>
<% end %>
Controller
def create
account = Account.getAccountById(session[:user])
message = Message.find(
params[:reply][:message_id],
:conditions => ["messages.account_id=? or messages.sender_id=?", account.id, account.id]
)
if message
#reply = Reply.new
#reply.message_id = message.id
#reply.sender_id = account.id
#reply.message = params[:reply][:message]
if #reply.save
flash[:message] = "Reply successfully submitted."
redirect_to(messages_path)
else
flash[:warning] = "Message cannot be blank."
redirect_to(messages_path)
end
else
redirect_to(messages_path)
end
rescue ActiveRecord::RecordNotFound
render :template => "error"
end
I'd appreciate any help provided. I'll keep trying to figure out what the problem is.
Thank you.
Update: Stacktrace
RAILS_ROOT: C:/Users/redbush/Desktop/biomixr
Application Trace | Framework Trace | Full Trace
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.8/lib/active_record /associations/association_proxy.rb:259:in `raise_on_type_mismatch'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.8/lib/active_record/associations/belongs_to_association.rb:22:in `replace'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.8/lib/active_record/associations.rb:1287:in `message='
C:/Users/redbush/Desktop/biomixr/app/controllers/replies_controller.rb:14:in `create'
Request
Parameters:
{"commit"=>"Reply",
"reply"=>{"message"=>"sssss",
"message_id"=>"4"},
"authenticity_token"=>"SMVfiolNAVPmLLU0eOWzx2jPFbujMtpyqQcs6A2Mxr0="}
Show session dump
Response
Headers:
{"Content-Type"=>"",
"Cache-Control"=>"no-cache"}
Your problem is that you have a relation to message and you also want to use a text field on the same model called message. When you create a relation you have access to some new methods that will step on the feet of other getter and setters.
To fix this change the name of the text field to another name and reflect the changes in your controller.
If you need more detail let me know.
The belongs_to relation creates a message attribute on your model, which expects an object of type Message. However, you also have a message attribute of type string. You can workaround this by using:
belongs_to :my_message, :class_name => :message
And the related message will be available as my_message, while the text field will be available as message.
In general, it seems like you're trying to handle too much of the relation work on your own - let rails do the work for you.
You have a clash in the design of your model. You have both an association and an attribute named message.
The error you are getting is because Rails is expecting you to fill up the association instead of the attribute.
I suggest changing your attribute from message to message_text, like so:
#reply = Reply.new
#reply.message_id = message.id
#reply.sender_id = account.id
#reply.message_text = params[:reply][:message]
Do make the changes in your migration file and run it too.