Could someone explain the following Ruby on Rails error? - ruby-on-rails

LoadError in CandidatesController#create
Unable to autoload constant Usermailer, expected Z:/railsassignment/student/app/mailers/usermailer.rb to define it
When I submit a form I get the error above. The form processes a record and the candidate is added to the database however the welcome email I'm trying to send to the newly registered candidate doesn't send, and the error above prevents the user from proceeding.
Candidates Controller
def create
#candidate = Candidate.new(candidate_params)
respond_to do |format|
if #candidate.save
Usermailer.welcome(#candidate).deliver_now ***<-- Error highlights this line***
format.html { redirect_to #candidate, notice: 'User was successfully
created.' }
format.json { render :show, status: :created, location: #candidate }
else
format.html { render :new }
format.json { render json: #candidate.errors, status:
:unprocessable_entity }
end
end
end
usermailer.rb
Z:/railsassignment/student/app/mailers/usermailer.rb (usermailer directory)
class UserMailer < ActionMailer::Base
default from: "from#example.com"
def welcome(candidate)
#candidate = candidate
mail(:to => candidate.can_email, :subject => "Welcome to EmployeMe.com, You
have registered successfully!")
end
end
Should you need to see any more of the files drop me a comment and I'll be quick to add them to the question.

It seems like a case of messed up naming convention.
As per Rails naming convention, file names should be in snake_case and class names in CamelCase. In your scenario, the file name should be user_mailer.rb.
So either rename usermailer.rb to user_mailer.rb
or
class name UserMailer to Usermailer.

Always use snake case for your file names.
Z:/railsassignment/student/app/mailers/user_mailer.rb
NOT:
Z:/railsassignment/student/app/mailers/usermailer.rb
Always use camel case for your class names
UserMailer.welcome(#candidate).deliver_now
NOT:
Usermailer.welcome(#candidate).deliver_now
If your interested in how constants loading works with rails you could take a gander at this.

Related

invalid signature error for edit product and new product form submission rails

Hi I am currently working on a web marketplace app for an assignment that allows users to upload items for sale with images attached, and to edit those listings.
Currently i have utilised simple forms for the edit and add product pages and those work fine but when I click update or add product I get the below error:
ActiveSupport::MessageVerifier::InvalidSignature in ProductsController#create
the error pointed out that line 3 of the below code is the problem:
def create
#product = Product.new(product_params)
#product.user_id = current_user.id
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: "Product was successfully created." }
format.json { render :show, status: :created, location: #product }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
My product.rb file looks as such:
belongs_to :user, :optional => true
has_one_attached :picture
end
The simple forms work but for reference the form html looks like such:
<%= simple_form_for#product do |f| %>
<h1 class="heading">Edit Product</h1>
<%= render 'form', product: #product %>
<% end %>
Any help I can get would be appreciated.
When you use the respond_to do |format| method, you need to supply the actual formats that the code should respond to. So, your controller probably needs to look something like this:
def create
#product = Product.new(product_params)
#product.user_id = current_user.id
respond_to do |format|
format.html do
if #product.save
...
end
end
end
But I'd also ask: why are you using respond_to here if you only expect to process the result of a web form? It's something you may need to do at some point, but isn't required initially and adds complication.
If that doesn't resolve the issue, we'll probably need to see your strong-params function (product_params), the Product model definition and your view, at least. For example, you may need to structure the line more like this, because your params may well not exactly match the fields in your model.
#product = Product.new(id: product_params[:id], name: product_params[:name])
Rails adds a special authentication code when it creates a form, to help stop bad actors from spamming or hacking your form. If your page is changed after the code is created, it will become out of date and be rejected, but I'd expect a more specific error if that was happening. Fingers crossed!

how to call actionmailer in rails admin controller?

I want to send a email to user after create something via rails admin.
I know I can call it in model callback but it's not considered as a good pratices
the best way is to put the actionmailer action after model save in the controller but I don't know how to do it in rails_admin controller
class UsersController < ApplicationController
# POST /users
# POST /users.json
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
# Tell the UserMailer to send a welcome email after save
UserMailer.welcome_email(#user).deliver_later
format.html { redirect_to(#user, notice: 'User was successfully created.') }
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: 'new' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
end
What you want to do is not easy on rails admin because you cannot modify the controllers nor do you have access to them without monkey patching them.
I actually made a fork of rails admin for this functionality checkout the commit with the changes:
https://github.com/aliada-mx/rails_admin/commit/6251554efd1d83cdb418f42683ee55a4e27c2474
Just touched two files
And example usage
class User
after_save :on_admin_updates
attr_accessor :edited_in_rails_admin
def on_admin_updates
return unless edited_in_rails_admin
self.edited_in_rails_admin = false
UserMailer.welcome_email(self.id)
end
end
A bit clunky i know, PR´s welcome.
Have you tried to include your Mailer in admin_controller?
include UserMailer
Then in your create action UserMailer.some_mailer_action.deliver_now

Rails Associations: belongs_to has_many confusion

I've read through the following tutorial and found the curious line:
notice that the create function is written in such a way that there has be a #post before creating a #comment.
You can see the supporting controller code:
Class CommentsController < ApplicationController
----
def create
#post = Post.find(current_post)
#comment = #post.comments.create(post_params) ## 'Essential stuff'
respond_to do |format|
if #comment.save
format.html { redirect_to action: :index, notice: 'Comment was successfully created.' }
format.json { render :show, status: :created, location: #comment }
else
format.html { render :new }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
----
end
Indeed, "current_post" implies that the post was created BEFORE the comment.
But what if I want both to be created simultaneously? For example, suppose my USER has_many EMAILS, and each EMAIL belongs_to a USER. Then, when creating a new user, I may want to have an expandable form that allows the user to add one, two, three, or twenty emails while creating his account.
How could this be done?
Nested Attributes is the rails way of doing what you want to achieve.
Checkout http://railscasts.com/episodes/196-nested-model-form-part-1
You need to consider using nested form, have a look into this gem, very easy to implement. It will allow the user to add multiple emails as required.

Rails: respond_with custom object

respond_with is acatually meant to use with ActiveModel's instances. I tried to use it with OpenStruct's instance, but it raises an error.
Is that ever possible to use respond_with with custom objects?
class CryptController < ApplicationController
respond_to :json
def my_action
respond_with OpenStruct.new(foo: 'foo', bar: 'bar')
end
# ...
end
Raises: **undefined method persisted?' for nil:NilClass**
ruby-2.1.4#rails4/gems/actionpack-4.2.5.1/lib/action_dispatch/routing/polymorphic_routes.rb:298:inhandle_list'
/home/workstat/.rvm/gems/ruby-2.1.4#rails4/gems/actionpack-4.2.5.1/lib/action_dispatch/routing/polymorphic_routes.rb:206:in polymorphic_method'
/home/workstat/.rvm/gems/ruby-2.1.4#rails4/gems/actionpack-4.2.5.1/lib/action_dispatch/routing/polymorphic_routes.rb:114:inpolymorphic_url'
respond_with is a helper method that exposes a resource to mime requests.
From the documentation
respond_with(#user)
for the create action, is equivalent (assuming respond_to :xml in the example) to:
respond_to do |format|
if #user.save
format.html { redirect_to(#user) }
format.xml { render xml: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.xml { render xml: #user.errors, status: :unprocessable_entity }
end
end
end
The precise equivalent is dependent upon the controller action.
The key takeaway is that respond_with takes a #instance variable as an argument and first attempts to redirect to the corresponding html view. Failing that, it renders an xml response, in the case above.
You are passing in an ostruct, which doesn't correspond to an instance of your model. In this case, respond_with doesn't know where to redirect to in your views and doesn't have an instance from which to render a mime response.
See this RailsCast and this blogpost from José Valim.
A note: The error undefined method persisted? is generated by Devise and probably because it can't find a route.

How should I update one model (table) from a different controller (or model)

I have a generic import table that allows the loading of csv files into different columns in my import table. The same import table is used for multiple types of imports, so I don't process the individual fields until the user is ready and tells me where to process it.
So in this case I have an import table with many cells that I will use to create (or update) donors in my donors table. How do I send my import_table data associated with the import_table model and controller to the create method of my donors_controller?
the create method of my donors_controller:
def create
# need to find donor by id if given, else use find_or_create_by_blahblahblah
unless #donor = Donor.find_by_id(params[:donor][:id])
#donor = Donor.find_or_initialize_by_company_and_prefix1_and_first_name1_and_last_name1_and_address1(params[:donor])
end
if #donor.new_record?
respond_to do |format|
if #donor.save
format.html { redirect_to #donor, notice: 'Donor was successfully created.' }
format.json { render json: #donor, status: :created, location: #donor }
else
format.html { render action: "new" }
format.json { render json: #donor.errors, status: :unprocessable_entity }
end
end
else
respond_to do |format|
if #donor.save
format.html { redirect_to #donor, notice: 'Donor already exists. Please edit donor if needed.'}
format.json { render json: #donor, status: :created, location: #donor }
else
format.html { render action: "new" }
format.json { render json: #donor.errors, status: :unprocessable_entity }
end
end
end
end
Then in my import_tables controller I have this method:
def process_import
#import = ImportTable.find(params[:id])
if #import.import_type == 'Prospects'
#do something here....
elsif #import.import_type == 'Donations'
#do something here...
end
end
I am not sure what exactly I should do in the #do something here... parts.
I was thinking I should pick out the right columns from #import and put them in [:donor] array and send them to the create method of my donors_controller, but I am not sure exactly how to do that or if that is the right way to go about this.
The missing link is that you need to get to the Class from it's name..
There are several ways to do this, e.g. with an "eval' , but a cleaner and simpler way to do this is to:
# do something:
class_name = #import.import_type
klass = ActiveRecord.const_get(class_name) # now you have a reference to your class
#... then do whatever you like with your symbolic klass, e.g. create your new entry
# klass.find_or_create(...) , klass.find(1), klass.first ,
# klass.create( {attributes for new instance of klass} )
this works so conveniently because in your model you do YourClass < ActiveRecord::Base ,
your class is part of the ActiveRecord module, Classes in Ruby are constants which are stored in the context in which they are defined (=in their module), therefore you can query that context, e.g. ActiveRecord, and find your class.
If your class was not derived from ActiveRecord::Base , you could still do a:
klass = Kernel.const_get( class_name )
see also:
http://infovore.org/archives/2006/08/02/getting-a-class-object-in-ruby-from-a-string-containing-that-classes-name/
if you are going line by line, Keep count of which line you are processing.
then in your #do something areas just call Prospect.new, Donation.new, etc.
validate or save it, and gather up all the errors reported by the object so that you can spit them back to the user with a line number of where the error occured.
You don't need to goto the specific controller methods for each type. Your import logic will basically handle it.

Resources