Rails Youtube_it gem background job - ruby-on-rails

I'm fairly new to Rails and I have a Ruby on Rails 3.2 application and I've integrated the Youtube_it gem seen here https://github.com/kylejginavan/youtube_it. The gem works fine and I'm able to upload the video to youtube, but it takes a while to process the video. I would like to be able to run that as a background job and redirect the user to the thank you page I have created.
I'm not sure where to call the delay method. I would like to call the delay method and then have the user redirect to the page_path('thank-you') page.
Any help would be greatly appreciated. I've searched all over for an answer.
VideosController
def upload
#video = Video.create(params[:video])
if #video
#upload_info = Video.delay.token_form(params[:video], save_video_new_video_url(video_id: #video.id))
else
respond_to do |format|
format.html { render "/videos/new" }
end
end
end
def save_video
#video = Video.find(params[:video_id])
if params[:status].to_i == 200
#video.update_attributes(youtube_id: params[:id].to_s, is_complete: true, user_id: current_user.id, approved: false)
Video.delete_incomplete_videos
else
Video.delete_video(#video)
end
#redirect_to videos_path, notice: "video successfully uploaded"
redirect_to page_path('thank-you')
end
Here is my controller.
class VideosController < ApplicationController
before_filter :authenticate_user!, only: [:new, :upload, :save_video, :destroy]
def index
if params[:category]
Video.yt_session
#videos = Video.approved.where(category_id: params[:category])
else
Video.yt_session
#videos = Video.approved
end
respond_to do |format|
format.html # index.html.erb
format.json { render json: #videos }
end
end
def show
#video = Video.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #video }
end
end
def new
#video =Video.new
#categories = Category.all
respond_to do |format|
format.html # new.html.erb
format.json { render json: #video }
end
end
def upload
#video = Video.create(params[:video])
if #video
#upload_info = Video.token_form(params[:video], save_video_new_video_url(video_id: #video.id))
else
respond_to do |format|
format.html { render "/videos/new" }
end
end
end
def save_video
#video = Video.find(params[:video_id])
respond_to do |format|
if #video.update_attributes(:youtube_id => params[:id].to_s, :is_complete => true,:user_id=>current_user.id,:approved=>false)
format.html { redirect_to page_path('thank-you') }
format.json { head :no_content }
else
format.html { Video.delete_video(#video) }
format.json { render json: #category.errors, status: :unprocessable_entity }
end
end
end
def destroy
#video = Video.find(params[:id])
if Video.delete_video(#video)
flash[:notice] = "Video deleted."
else
flash[:error] = "We were unable to delete this video."
end
redirect_to videos_path
end
def vote_up
#video = Video.find(params[:id])
#video.update_attribute(:votes_up, (#video.votes_up.to_i + 1))
redirect_to #video
end
protected
def collection
#videos ||= end_of_association_chain.completes
end
end

You can always use background workers to do that using the like of delayed_job, but personally speaking I prefer to use Resque/beanstalkd/RabbitMQ since I can run multiple workers, concurrently.
To make your life even easier, you just try Sidekiq (https://github.com/mperham/sidekiq).
You will move your worker logic to some worker.
Include Sidekiq to your Gemfile
gem 'sidekiq'
At your controller add something like:
VideoSaverWorker.perform_async(#video.id)
The VideoSaverWorker must look something like:
class VideoSaverWorker
include Sidekiq::Worker
sidekiq_options queue: "high"
def perform(video_id)
video = Video.find(video_id)
.....
.....
end
end
Please note using this you will do the work at a background thread, but it wont redirect you to the related page.
You will need to do some workarounds, something like periodically refrishing the page till you see the changes at your view html page, or maybe you can push the changes to your webpage using Faye or Node.js.

Related

Redirect to a post with specific name from user input in Ruby on Rails?

I am a newbie in RoR, thus sorry for stupid question :(
I have a Game model, with a code string. There is a welcome/index view in my app with a simple form_to input. I wish to redirect user to a Game with a specific code after he submits the form.
I understand that I should somehow combine a .where method and redirect_to in Welcome_controller, but I just can't figure out how...
Welcome_controller.rb:
class WelcomeController < ApplicationController
def index
end
def redirect
redirect_to ?game with a code that equals :param from input?
end
end
Welcome/index:
<h1>Let's join the game!</h1>
<%= form_tag redirect_path do %>
<%= text_field_tag(:param) %>
<%= submit_tag("Search") %>
<% end %>
routes.rb:
Rails.application.routes.draw do
get 'welcome/index'
resources :games
get 'games/index'
root 'welcome#index'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
game.rb:
class Game < ApplicationRecord
validates :name, :presence => true
end
games_controller:
PREFACE = ('A'..'Z').to_a << ?_
SUFFIX = ('0'..'9').to_a
PREFACE_SIZE = 2
SUFFIX_SIZE = 3
class GamesController < ApplicationController
before_action :set_game, only: %i[ show edit update destroy ]
# GET /games or /games.json
def index
#games = Game.all
end
# GET /games/1 or /games/1.json
def show
end
# GET /games/new
def new
#game = Game.new
#game.code = gen_name
end
def gen_name
PREFACE.sample(PREFACE_SIZE).join << SUFFIX.sample(SUFFIX_SIZE).join
end
# GET /games/1/edit
def edit
end
# POST /games or /games.json
def create
#game = Game.new(game_params)
respond_to do |format|
if #game.save
format.html { redirect_to game_url(#game), notice: "Game was successfully created." }
format.json { render :show, status: :created, location: #game }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #game.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /games/1 or /games/1.json
def update
respond_to do |format|
if #game.update(game_params)
format.html { redirect_to game_url(#game), notice: "Game was successfully updated." }
format.json { render :show, status: :ok, location: #game }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #game.errors, status: :unprocessable_entity }
end
end
end
# DELETE /games/1 or /games/1.json
def destroy
#game.destroy
respond_to do |format|
format.html { redirect_to games_url, notice: "Game was successfully destroyed." }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_game
#game = Game.find(params[:id])
end
# Only allow a list of trusted parameters through.
def game_params
params.require(:game).permit(:code, :name)
end
end
In config/routes.rb you have defined resources :games, which creates default paths for CRUD actions. For the show action, which you are trying to get here, it would lead to /games/:id and the helper method would be game_path. You can also check this by running rails routes -c games command in the app directory. It should return all paths for games_controller
In the before_action callback for GamesController#show action, you are finding a Game object using Game.find(params[:id]). :id parameter is what you need to pass to the path helper that I mentioned earlier for the action to fire properly, so the path to a specific game would look like game_path(id: game.id). This will then automatically get converted to params. Alternatively, you can just pass the game object to the path helper and it will do the job for you like this: game_path(game)
Now in the WelcomeController#redirect action, you get the game code in params from the form submit. You need to first find the game for the submitted code like this:
game = Game.find_by(code: params[:param])
This should work if the code is unique for each game. Now that you have the correct game record, all you need is to redirect to the path that I've mentioned eariler:
redirect_to game_path(game)

ROR Scaffold Destroy redirect_to

I actually built a 'Offer' scaffold referenced to user (devise) and product. I can add an offer on the specific product page. However, I realise when I try to delete an offer, it is by default redirected to products_url. How can I redirect it back to the specific product page? When I create the comment, it does redirect_to the specific product page. Delete doesnt do so.
I have tried using
Original code
class OffersController < ApplicationController
before_action :set_offer, only: [:show, :edit, :update, :destroy]
def index
#offers = Offer.all
end
def show
end
def new
#offer = Offer.new
end
# GET /offers/1/edit
def edit
end
# POST /offers
# POST /offers.json
def create
#product = Product.find(params[:product_id])
#offer = #product.offers.new(offer_params)
#offer.user = current_user
respond_to do |format|
if #offer.save
format.html { redirect_to #product, notice: 'Offer was successfully created.' }
format.json { render json: #product, status: :created, location: #offer }
else
format.html { render action: "new" }
format.json { render json: #offer.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /offers/1
# PATCH/PUT /offers/1.json
def update
respond_to do |format|
if #offer.update(offer_params)
format.html { redirect_to #offer, notice: 'Offer was successfully updated.' }
format.json { render :show, status: :ok, location: #offer }
else
format.html { render :edit }
format.json { render json: #offer.errors, status: :unprocessable_entity }
end
end
end
# DELETE /offers/1
# DELETE /offers/1.json
def destroy
#offer.destroy
respond_to do |format|
format.html { redirect_to product_url, notice: 'Offer was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_offer
#offer = Offer.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def offer_params
params.require(:offer).permit(:product_id, :priceOffer, :user_id)
end
end
I tried to modify
def destroy
#offer.destroy
respond_to do |format|
format.html { redirect_to #product, notice: 'Offer was successfully destroyed.' }
format.json { head :no_content }
end
end
It actually showed my error. The 26 is actually offer_id. It should actually redirect to http://localhost:3000/products/18 . It showed me the extracted source as below.
Couldn't find Product with 'id'=26
def set_product
#product = Product.find(params[:id])
end
I am not sure I've understood the question but I think you just need to pass the product's id as an additional parameter, something like:
= link_to 'destroy', offer_path(#offer, product_id: #product.id), method: :delete
and then in your controller use
redirect_to product_path(params[:product_id])
Do this in destroy method.
Product =#offer.product
redirect_to :product
#product you have used is not set. So we need to set product_id here.
That's why we took product id from offer variable through relation
what you did in set_product just use params[:id] to find product, but the params[:id] is refer to the offer_id when you call destroy, that's why you get the RecordNotFoundError. I think you can write this.
def set_product
# maybe you should judge whether #product is nil or not
#product = #offer.product
end

NoMethodError Rails 3.2

I've been searching all over and can't find the answer to this anywhere.
I'm taking the intro to RoR course on udemy, and I've been able to solve all the problems I've had in the first 80% of the course, but now I'm at a roadblock and can't find this. We're building an app like Etsy, and I'm at the point where I need to restrict users from editing/deleting listings that don't belong to them.
I'm running Ruby 1.9.3 on Rails 3.2.21
I tried following the instructions for adding the check user filter, but when I checked back on local host, I received this error:
NoMethodError in ListingsController#edit
undefined method `user' for nil:NilClass
app/controllers/listings_controller.rb:98:in `check_user'
Parameters:
{"id"=>"8"}
My code matches the instructor's code exactly, but I think this error is because I'm using Rails 3, and he's using 4.
Here's my listings_controller.rb
class ListingsController < ApplicationController
# GET /listings
# GET /listings.json
before_filter :authenticate_user!, only: [:new, :create, :edit, :update, :destroy]
before_filter :check_user, only: [:edit, :update, :destroy]
def index
#listings = Listing.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #listings }
end
end
# GET /listings/1
# GET /listings/1.json
def show
#listing = Listing.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #listing }
end
end
# GET /listings/new
# GET /listings/new.json
def new
#listing = Listing.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #listing }
end
end
# GET /listings/1/edit
def edit
#listing = Listing.find(params[:id])
end
# POST /listings
# POST /listings.json
def create
#listing = Listing.new(params[:listing])
#listing.user_id = current_user.id
respond_to do |format|
if #listing.save
format.html { redirect_to #listing, notice: 'Listing was successfully created.' }
format.json { render json: #listing, status: :created, location: #listing }
else
format.html { render action: "new" }
format.json { render json: #listing.errors, status: :unprocessable_entity }
end
end
end
# PUT /listings/1
# PUT /listings/1.json
def update
#listing = Listing.find(params[:id])
respond_to do |format|
if #listing.update_attributes(params[:listing])
format.html { redirect_to #listing, notice: 'Listing was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #listing.errors, status: :unprocessable_entity }
end
end
end
# DELETE /listings/1
# DELETE /listings/1.json
def destroy
#listing = Listing.find(params[:id])
#listing.destroy
respond_to do |format|
format.html { redirect_to listings_url }
format.json { head :no_content }
end
end
private
def set_listing
#listing = Listing.find(params[:id])
end
def listing_params
params.require(:listing).permit(:name, :description, :price, :image)
end
def check_user
if current_user != #listing.user
redirect_to root_url, alert: "Sorry, this listing belongs to someone else."
end
end
end
The code that we had to add for this is the second before_filter and the def check_user
If any other information is needed to help answer this, please let me know.
It's not a Rails 3 vs 4 issue, your code never calls set_listing and so #listing is never being set. You should probably have a:
before_filter :set_listing, only: [:show, :edit, :update, :destroy]
at the top of your file, before the before_filter :check_user, ...

Rails 4 default respond_to for ajax controller

I have a rails controller where every action has the same respond_to block for every action, eg:
def some_action
respond_to do |format|
format.html { redirect_to :back }
format.js { render layout: false }
end
end
Is there a way that I can set this as the default response for all actions? I know that I can use
respond_to :html, :js
at the top of the controller, but can this be used to set the specific responses for each format?
Going though respond_with and respond_to documentation and source code. You can either
Use respond_to
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
flash[:notice] = 'User was successfully created.'
format.html { redirect_to(#user) }
format.xml { render xml: #user }
else
format.html { render action: "new" }
format.xml { render xml: #user }
end
end
end
OR respond_with
respond_to :html, :xml
def create
#user = User.new(params[:user])
flash[:notice] = 'User was successfully created.' if #user.save
respond_with(#user)
end
A work around is to create your own custom respond method, or manually check for the mime type as follows:
****NOTE: this is a really bad practice, I recommend sticking to conventions.
def some_action
render json: {"a" => "s"} if request.format.json?
render :some_action if request.format.html?
end
If you want all actions to respond exactly the same, move the respond_to block into a method.
def some_action
# do things
respond
end
def another_action
# do more things
respond
end
def special_action
# do special things
respond
end
private
def respond
respond_to do |format|
format.html { redirect_to :back }
format.js { render layout: false }
end
end
This will DRY up your controller, which I assume was the question.

Mailboxer JSON Format

I am using the mailboxer gem and I wanted to go about making the conversation (show.html.haml) JSON format and also the mailbox (index.html.haml) JSON format.
I tried putting it a normal respond_to block like this
respond_to do
format.json { render :json => #conversation }
end
but it didn't work. It says the stack level is too deep. Is there something I'm missing?
These are the controller code
def mailbox
#mailbox ||= current_user.mailbox
end
def conversation
#conversation ||= mailbox.conversations.find(params[:id])
end
I ended up figuring out what the problem was, I needed to add a show and index into my conversations controller so that I could then render in json. For anyone else that may have this problem this was what I did and it worked fine.
def index
#mailbox ||= current_user.mailbox
respond_to do |format|
format.html
format.json { render :json => #mailbox }
end
end
def show
#conversation ||= mailbox.conversations.find(params[:id])
respond_to do |format|
format.html
format.json { render :json => #conversation }
end
end
Hope this helps!

Resources