I've been pulling my hair out trying to get anything working with "def create" and "def update" in the users_controller.rb for Devise.
For instance, I've tried this:
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
flash[:notice] = "Test Save"
else
flash[:notice] = "Test Error"
end
end
end
I've used this code along with the appropriate code to show flash notices in the views section. However nothing is shown when I either submit a blank form, an incomplete form, or a complete form. The user registration will still go through on a complete form, but it does not follow anything I put in "def create". I've tried other ways of testing this aside from flash notices, such as sending to a different page, etc. I get no response. The same thing for "def update", it doesn't seem to even use that code.
I'm completely dumbfounded on this one, any ideas?
If i understand your question correctly, you should be overwriting the devise controller.
# app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def new
super
end
def create
# add custom create logic here
end
def update
super
end
end
You can see what the default devise controllers are doing here:
https://github.com/plataformatec/devise/tree/master/app/controllers/devise
If you just want to edit the flash message, looking at the link above shows that devise uses a method called set_flash_message
# Sets the flash message with :key, using I18n. By default you are able
# to setup your messages using specific resource scope, and if no one is
# found we look to default scope.
# Example (i18n locale file):
#
# en:
# devise:
# registrations:
# signed_up: 'Welcome! You have signed up successfully.'
So you can just edit your devise.en.yml file with the correct text and voila!
Note: If you do overwrite the controller don't forget to also add
# app/config/routes.rb
devise_for :users, :controllers => {:registrations => "registrations"}
How about this instead?
if #user.save
redirect_to #user, notice: 'User was successfully created.'
else
render action: 'new'
end
You are setting the flash, but no redirection and no rendering. I'm wondering if you are getting a blank page, or a 200 with no body.
This will redirect to the show action, setting a flash notice if successful and render the new form with the #user.errors showing why it failed.
If you are using devise, you could use the Registrations Controller to create a new account, you shouldn't need to create a new one. If you create a new one, there might be a conflict in the routes with registrations#create and users#create both pointing to POST /users
Related
In my rails application I've created a business daily report. There is some non-trivial logic for showing it (all kind of customizable parameters that are used for filtering in the model, a controller that calls that model and some non-trivial view for it, for example, some of the columns are row-spanning over several rows).
Now I wish to send this report nightly (with fixed parameters), in addition to the user ability to generate a customize report in my web site. Of course, I wish not to re-write/duplicate my work, including the view.
My question is how can I call the controller action from my mailer so that it will be as if the page was requested by a user (without sending a get request as a browser, which I wish to avoid, of course)?
In answer to your question is if you are generating some sort of pdf report then go with using the wicke_pdf gem does exactly that generates pdfs. To send a report on a nightly basis the best thing for this is to implement some sort of cron job that runs at a particular time which you can do using the whenever gem. You can do something like:
schedule.rb
every :day, :at => '12:00am'
runner User.send_report
end
With this at hand you can see that you call the send_report method sits inside the User model class as shown below:
User.rb
class User < ActiveRecord::Base
def self.send_report
ReportMailer.report_pdf(#user).deliver
end
end
Inside send_report we call the mailer being ReportMailer which is the name of the class for our mailer and the method being report_pdf and pass in the user. BUT remember this is an example I have here I am not sure the exact specified information you want in a report.
Mailer
class ReportMailer< ActionMailer::Base
default :from => DEFAULT_FROM
def report_pdf(user)
#user = user
mail(:subject => "Overtime", :to => user.email) do |format|
format.text # renders report.text.erb for body of email
format.pdf do
attachments["report.pdf"] = WickedPdf.new.pdf_from_string(
render_to_string(:pdf => "report",:template => 'report/index.pdf.erb',
:layouts => "pdf.html"))
end
end
end
end
Inside the mailer there are a variety of things going on but the most important part is inside the format.pdf block that uses a variety of wicked_pdf methods (this is assuming that you are using wicked_pdf btw. Inside the block you create a new WickedPDF pdf object and render it to a string. Then provide it with the name of the report, the template and the layout. It is important that you create a template. This usually will where the report will be displaying from. The file type is a .pdf.erb this means that when this view or report is generated in the view the embedded ruby tags are being parsed in and the output is going to be a pdf format.
UserController
def report
#user = User.scoped
if params[:format] == 'pdf'
#Do some stuff here
User.send_report(#users)
end
respond_to do |format|
format.html
format.pdf do
render :pdf => "#{Date.today.strftime('%B')} Report",
:header => {:html => {:template => 'layouts/pdf.html.erb'}}
end
end
end
The key thing you asked that I picked up on.
how can I call the controller action from my mailer
In the controller simply collate a scope of Users, then check the format is a pdf, providing it is do some stuff. Then it will run the method send_report which I earlier highlighted in the user model class (Btw in your words this is the controller calling the model). Then inside the respond block for this there is a format.pdf so that you can generate the pdf. Once again note that you need a template for the core design of the pdf, which is similar to how rails generates an application.html.erb in the layouts. However here we have a pdf.html.erb defined. So that this can be called anywhere again in your application should you want to generate another pdf in your application somewhere else.
Think I've provided a substantial amount of information to set you off in the right direction.
I know that you can override the default devise controllers and I did so for the Registrations and Sessions Controller. I know that you can also change the text for the flash messages in devise under locale. However, I am not sure how to change the type of flash message showing for the sessions controller when there is an invalid combination of username and password.
The create method looks like
def create
self.resource = warden.authenticate!(auth_options)
set_flash_message(:notice, :signed_in) if is_navigational_format?
sign_in(resource_name, resource)
respond_with resource, :location => after_sign_in_path_for(resource)
end
I suspect that the validation is done during the follow call
warden.authenticate!(auth_options)
But this is where I am not sure how to overwrite that in my app.
Also, I think it is a complex override for such a simple use case of changing the color of a flash notice.
Any insights would be much appreciated.
Thanks!
Nick
You can do it with custom failure app. As you can see this flash message is setting right here So you can change it in your custom failure app.
So at first you inherit your failure app from Devise's one:
class CustomFailure < Devise::FailureApp
def recall
env["PATH_INFO"] = attempted_path
flash.now[:error] = i18n_message(:invalid)
self.response = recall_app(warden_options[:recall]).call(env)
end
end
place this file somewhere in your app and say Devise to use it like this (config/initializers/devise.rb):
config.warden do |manager|
manager.failure_app = CustomFailure
end
My controller is using the default RESTful routes for creating, adding, editing etc
I want to change the default :id to use :guuid. So what I did was:
# routes.rb
resources :posts
# Post Model
class Post < ActiveRecord::Base
def to_param # overridden
guuid
end
end
This works but my modifed REST controller code has something like this
def show
#post = Post.find_by_guuid(params[:id])
#title = "Review"
respond_to do |format|
format.html # show.html.erb
end
end
When I see this this code ..
Post.find_by_guuid(params[:id])
it would seem wrong but it works.
I don't understand why I can't write it out like this:
Post.find_by_guuid(params[:guuid])
Why do I still have to pass in the params[:id] when I'm not using it?
Looking for feedback on whether my approach is correct or anything else to consider.
Even though it works it doesn't always mean it's right.
Type rake routes in your console, and check the output of the routes. You'll see the fragment ':id' in some of them, that's where the params[:id] comes from. It's a rails convention : when you use resources in your routes, the parameter is named id. I don't know if you can change it (while keeping resources; otherwise you could just go with matching rules), but you shouldn't anyway : even if it seems not very logic, it actually has sense, once your understand how rails routing works.
I'm new to Rails and currently using Rails 3, so please bear with me. I have a basic app, with a basic scaffolded controller/model e.g Contacts.
Amongst the methods for Show/Edit etc.. i have added a method called newcontacts (i have also added a newcontacts.html.erb), which will eventually show the last 5 contacts imported , but at the moment i am using the same code one would find in the basic Index method of a controller (i intend to filter the data at a later point), the method in the controller is -
def newcontacts
#contacts = Contact.all
respond_to do |format|
format.html # index.html.erb
end
end
I can access localhost:3000/contacts which displays the index method action from the contact controller, but when i try and access this method (newcontacts) using localhost:3000/contacts/newcontacts it returns the error
Couldn't find Contact with id=newcontacts
I have looked at the routes.rb file as i believe this is what needs editing, and have added the following line to routes.rb
match 'newcontacts', :to => 'contacts#newcontacts'
but this only works when i call localhost:3000/newcontacts.
So my question is, how do i get the url localhost:3000/contacts/newcontacts to work?
Any help would be great.
I think what you're trying to do is add another RESTful action.
resources :contacts do
# This will map to /contacts/newcontacts
get 'newcontacts', :on => :collection # Or (not and; use only one of these)...
# This will map to /contacts/:id/newcontacts
get 'newcontacts', :on => :member # ... if you want to pass in a contact id.
end
Try this in your routes.rb file:
resources :contacts do
member do
put 'newcontacts'
end
end
That will add in a new action for the contacts controller.
I'm working on an e-commerce application. When a user logs into my app, I want to make a check to my external subscription handler and make sure that their subscription is still active and not expired/failed/whatever.
I successfully figured out how to use a Warden callback in my initializers/devise.rb to perform a check on the model after login. However, if there is a problem, I want to log them out again and redirect to a certain page that tells them what to do next.
Here is what I have. I know I can't use redirect_to from the callback. Given that, what is the best way to do what I'm trying to do?
Warden::Manager.after_authentication do |user, auth, opts|
begin
user.check_active_subscription # this works, and will raise one of several exceptions if something is goofy
rescue
redirect_to "/account/expired" # obviously this won't work, but see what I'm trying to do?
end
end
Just let the callback raise the exception and rescue from it in your controller. E.g.:
Warden::Manager.after_authentication do |user, auth, opts|
user.check_active_subscription
end
class SessionsController < ApplicationController
def create
# Authenticate
rescue SubscriptionExpiredException
# Logout
redirect_to "/account/expired"
end
end
You could also use rescue_from in your ApplicationController like this:
class ApplicationController
rescue_from SubscriptionExpiredException, :with => :deny_access
def deny_access
redirect_to "/account/expired"
end
end