how to call actionmailer in rails admin controller? - ruby-on-rails

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

Related

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 web shop with Devise login and current_user

I am making a web shop application in Rails with Devise as a login gem. The structure is as follows:
A user table which has a basket_id column and in its model I have set has_one :basket
The basket table belongs_to :user
In my basket_controller.rb I want to use the create method to get the user
# POST /baskets
# POST /baskets.json
def create
#basket = Basket.new(basket_params)
#basket.user_id = current_user.id
respond_to do |format|
if #basket.save
format.html { redirect_to #basket, notice: 'Basket was successfully created.' }
format.json { render :show, status: :created, location: #basket }
else
format.html { render :new }
format.json { render json: #basket.errors, status: :unprocessable_entity }
end
end
The problem is that the current_user method that should be automatically generated by Devise is not found and therefore the user_id in the Baskets table is not set. Also I have no idea where would I set the basket_id in the Users table or this should be done automatically because of the relationship defined in the models?
Any help would be appreciated. Thanks!
For current_user to work you need to add before_filter :authenticate_user! to your controller. If that does not work maybe is a csrf problem that you can solve placing
= csrf_meta_tags
In your layout.

Ruby on Rails URL Format

I have a Ruby on Rails application where you can create 'posts'. I started of by using the scaffold generator to give generate the title which is a string and the body which is the content.
Each 'post' has a url of the id, for example /1, /2, /3, etc.
Is there a way to change that to a string of random characters, for example /49sl, /l9sl, etc?
Update
Here is what I have for the posts_controller.rb
class PostsController < ApplicationController
# GET /posts
# GET /posts.json
def index
#posts = Post.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #posts }
end
end
# GET /posts/1
# GET /posts/1.json
def show
#post = Post.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #post }
end
end
# GET /posts/new
# GET /posts/new.json
def new
#post = Post.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #post }
end
end
# GET /posts/1/edit
def edit
#post = Post.find(params[:id])
end
# POST /posts
# POST /posts.json
def create
#post = Post.new(params[:post])
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render json: #post, status: :created, location: #post }
else
format.html { render action: "new" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PUT /posts/1
# PUT /posts/1.json
def update
#post = Post.find(params[:id])
respond_to do |format|
if #post.update_attributes(params[:post])
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post = Post.find(params[:id])
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url }
format.json { head :no_content }
end
end
end
Rails uses the to_param method of an ActiveRecord object in order to resolve it into a URL.
Assuming you have a way to generate these unique ids (referring to it as IdGenerator) you can do the following:
1- Generate this id whenever you persist a Post object and save it to the database, let's say under the column url_id
class Post < ActiveRecord::Base
before_create :generate_url_id
def generate_url_id
self.url_id = IdGenerator.generate_id
end
end
2- Inside your Post model override the to_param method:
class Post < ActiveRecord::Base
def to_param
return url_id
end
end
Now post_path(#post) will resolve to /posts/url_id
By the way, you can use SecureRandom.urlsafe_base64 or look here if you don't have an ID generator yet.
Read more on the documentation for to_param.
I hope these two resources are going to help you :
The gem , named obfuscate_id . It represents the ID in a format like :
http://tennisfans.eu/products/4656446465
Another gem - masked_id . It provides a similar functionality . You are in control with a format of the url creation , defining it in a class . Looking at the source it appears , that this gem uses a strategy of obfuscate_id gem .
You can give your posts random URLs by following these 3 steps:
1- In your model (Post.rb), generate a random string for each post before it is saved. For example,
class Post < ActiveRecord::Base
before_create :generate_url_id
def generate_url_id
self.url_id = SecureRandom.urlsafe_base64
end
end
2- In your model (Post.rb), supply a to_param method to override Rails default URL generation. For example:
class Post < ActiveRecord::Base
def to_param
self.url_id
end
end
3- In your controller (PostsController.rb), use a dynamic finder to find your post by its random string. For instance,
class PostsController < ApplicationController
def show
#post = Post.find_by_url_id(params[:id])
...
end
end
I went ahead and put together a complete example and posted it to Github.
Next to Erez manual way you can use the friendly_id gem, with a unique id as your slug.
class Post < ActiveRecord::Base
# FriendlyId
friendly_id :uid
# Set a unique user id on create
before_save :set_uid, on: :create
def set_uid
self[uid] = rand(36**8).to_s(36)
end
end
Please note that the setting of the uid here does not ensure uniqueness. You certainly need to add some kind of validation, but that whole topic is a different one to google.
Friendly_id is a good solution, if you want to use a gem for it.
Follow this screencast:
http://railscasts.com/episodes/314-pretty-urls-with-friendlyid
(either video or asciicast, as you prefer)
Screencasts by Ryan Bates are really well done.
If you still want another option for id generation, you can try using UUIDs:
https://en.wikipedia.org/wiki/Universally_unique_identifier
And a ruby gem to generate them easily:
https://github.com/assaf/uuid
However, I would ask: Why do you want to make them random anyway? If what you are trying to do
is to avoid one of your users from typing another id in the url and accessing data that is not theirs, then probably you would want to limit access in the controller by scoping the finder, with something like this:
def show
#post = current_user.posts.where(:id => params[:id]).first
respond_to do |format|
format.html # show.html.erb
format.json { render json: #post }
end
end
In this case, current_user is a function that returns the current authenticated user (from session, or whatever you application logic dictates).

Rails: Pass Parameters to New Controller during 'redirect_to'

I'm using Ryan Bates' Rails Cast on Wicked Wizard Forms to create a multi-step form. I don't have a current_user method defined (not using an authentication gem) - so, I'm trying to pass the user.id parameter during the redirect_to - unfortunately, I can't seem to get it to work. Any help is appreciated!
My user controller create method
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to controller: 'user_steps', id: 'user.id' }
#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
The user_steps controller that to which I am redirecting:
class UserStepsController < ApplicationController
include Wicked::Wizard
steps :gender, :items, :brands, :final
def show
render_wizard
end
end
You should pass it through as a param, ideally, which the redirect_to method will do for you if you use a proper route path.
Example:
redirect_to(user_steps_path(#user))
In your case, if you don't have a named route, you might do this:
redirect_to(controller: 'user_steps', id: #user.to_param)
In URLs it's advisable to use the to_param method. id is used for database queries.
What you're passing in is literally 'user.id' as a parameter. It will not be evaluated.

Curl POST to Rails application when controller looks like this

I'm trying to curl POST my Rails application in order to create a new Entry object. The problem is my entries_controller Create action looks like this:
def create
#user = current_user
#entry = #user.entries.build(params[:entry])
respond_to do |format|
if #entry.save
format.html { redirect_to landing_page_url, notice: 'Entry was successfully created.' }
format.json { render json: #entry, status: :created, location: #entry }
else
format.html { render action: "new" }
format.json { render json: #entry.errors, status: :unprocessable_entity }
end
end
end
Calling #user.entries.build just returns an exception because current_user doesn't exist. The thing is the Create action works well when I use the browser to create an Entry (as I login and create the current_user variable) but I do not know if it's possible to curl POST and create an Entry without changing the controller logic. And if it's not possible, could someone help reach the right direction towards building the controller logic (compatible with curl POST)?
I'm sorry if this is a dumb question, I'm fairly new to all this.
PS: I'm using Rails 3.2.3, if that's of any help.
Not sure how you create current_user (what it's based off), but this must exist for your method to work.
If you can pass a param to your action that specifies the user and set current_user as current_user ||= params[:user]... beware of the security implications of this.
You really should have a before_filter on your action to set current_user (via login, I'm presuming).

Resources