How to redirect to next question after showing the result for 2s Ruby on Rails / Turbo - ruby-on-rails-7

I am working on a quiz functionality, and I'd like to show the user the results for 2s before redirecting him to the next question.
Here is my code to show the results to the user (it works):
def validate_answer
answer_given = params[:answer_given]
quiz_question_id = params[:quiz_question_id]
next_question_id = params[:next_question_id]
is_right_answer = is_right_answer(Question.find(params[:question_id]), answer_given)
#quiz_question = QuizQuestion.update(quiz_question_id,answer_given:answer_given,is_answer_right:is_right_answer)
#question = Question.find(params[:question_id])
#card = #question.card
respond_to do |format|
format.turbo_stream do
render turbo_stream: [
turbo_stream.update('questionPartialId', partial: "questionPartial"),
]
end
end
end
Now if I add the sleep & redirect it does not work as the sleeps blocks the whole app (see code below)
How should I do to perform this sleep ?
def validate_answer
answer_given = params[:answer_given]
quiz_question_id = params[:quiz_question_id]
next_question_id = params[:next_question_id]
is_right_answer = is_right_answer(Question.find(params[:question_id]), answer_given)
#quiz_question = QuizQuestion.update(quiz_question_id,answer_given:answer_given,is_answer_right:is_right_answer)
#question = Question.find(params[:question_id])
#card = #question.card
respond_to do |format|
format.turbo_stream do
render turbo_stream: [
turbo_stream.update('questionPartialId', partial: "questionPartial"),
]
end
end
sleep(2)
if next_question_id != ""
redirect_to(question_path(next_question_id))
else
redirect_to(quiz_path(QuizQuestion.find(quiz_question_id).quiz_id))
end
end
Thanks a lot in advance !

Related

Updated version of file is not applied

I have file, which should be updated after updating instance attributes
It looks like this:
controller.rb
def update
if UpdateNewspaperDesign.new(newspaper_design, newspaper_design_params).call
#render response
end
end
and
class UpdateNewspaperDesign
def initialize(newspaper_design, params)
#newspaper_design = newspaper_design
#params = params
end
def call
newspaper_design.assign_attributes(params)
File.open(File.join(Rails.root, 'tmp', "newspaper-design-#{Time.now.to_i}.css"), 'w') do |file|
file.write(css(newspaper_design))
newspaper_design.css = file
end
newspaper_design.save
end
private
attr_reader :newspaper_design, :params
def css(newspaper_design)
NewspaperDesignCssCompiler.new(newspaper_design).call
end
end
And then I include css in layout
= stylesheet_link_tag newspaper.design.css_url, media: 'all'
As I see in console: css url is updated, but the url, which is inserted in layout - is not update.
Replace File with Tempfile
- this is how I fixed it

carrierwave uploader validates :presence => true not working

model/songs.rb
require 'file_size_validator'
class Song < ActiveRecord::Base
mount_uploader :attachment, AttachmentUploader
validates :attachment, :presence => true,
:file_size => {:maximum => 2.megabytes.to_i}
end
new.html.erb
<div class="well">
<%= form_for #song, html: { multipart: true } do |f| %>
<%= f.label :attachment %>
<%= f.file_field :attachment %>
<%= f.submit "Upload", class: "btn btn-primary" %>
<% end %>
</div>
when I submit empty form or form without file selection it gives error as :-
ActionController::ParameterMissing at /songs
param is missing or the value is empty: songs
actionpack (4.1.4) lib/action_controller/metal/strong_parameters.rb
182 def require(key)
183 self[key].presence || raise(ParameterMissing.new(key))
184 end
I'm wondering why ActiveRecords::Base validates :presence => true not working.
(new bie to rials)
songs_controller.rb
require 'zip'
require 'taglib'
class SongsController < ApplicationController
respond_to :html, :js
def index
session[:ids] = nil
#songs = Song.where("song_name IS NOT NULL AND song_path IS NOT NULL").page(1).per(5)
end
def new
#song = Song.new
#songs = Song.find(session[:ids]) if !session[:ids].nil?
end
def create
#song = Song.new(song_params)
if #song.save
puts #song.errors.messages
zip_file_path = Pathname.new(#song.attachment.current_path)
destination_path = zip_file_path.dirname
unzip(zip_file_path, destination_path, true) if zip_file_path.extname == ".zip"
session[:ids] = Array.new
Dir.glob("#{destination_path}" + '/*') do |music_files|
if %w(.mp3 .wav .aac .wma .m4a).include? File.extname(music_files)
song_details = extract_music_metadata(music_files)
if !song_details.nil?
#song = Song.new(song_details)
session[:ids].push(#song.id) if #song.save
end
else
File.delete(music_files)
end
end
redirect_to new_song_url, notice: "The contents of zip files are listed below !!!"
else
render "new"
end
end
def edit
#song = Song.find(params[:id])
end
def update
#songs = Song.where("song_name IS NOT NULL AND song_path IS NOT NULL").page(1).per(5)
#song = Song.find(params[:id])
#song.update_attributes(song_params)
if !session[:ids].nil?
#songs = Song.find(session[:ids])
end
end
def delete
#song = Song.find(params[:id])
end
def destroy
#songs = Song.where("song_name IS NOT NULL AND song_path IS NOT NULL").page(1).per(5)
#song = Song.find(params[:id])
#song.destroy
File.delete(#song.song_path)
if !session[:ids].nil?
#songs = Song.find(session[:ids])
end
end
private
def song_params
params.require(:song).permit(:attachment, :title, :artist, :album, :year, :track,
:genre, :comment)
end
# extract contents of a zip file
def unzip(zip, unzip_dir, remove_after = false)
Zip::File.open(zip) do |zip_file|
zip_file.each do |f|
f_path=File.join(unzip_dir, f.name)
FileUtils.mkdir_p(File.dirname(f_path))
a = zip_file.extract(f, f_path) unless File.exist?(f_path)
end
end
FileUtils.rm(zip) if remove_after
end
def extract_music_metadata(music_files)
TagLib::FileRef.open(music_files) do |fileref|
unless fileref.null?
tag = fileref.tag
song_details = {
song_name: File.basename(music_files),
song_path: music_files,
title: tag.title,
artist: tag.artist,
album: tag.album,
year: tag.year,
track: tag.track,
genre: tag.genre,
comment: tag.comment
}
end
end
end
end
Error from console is:
Started POST "/songs" for 127.0.0.1 at 2014-10-16 11:45:10 +0545
Processing by SongsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"oLgt6szICw1/4FIiP4dQk2IGSPqQb3l7roS0E1l7ovk=", "commit"=>"Upload"}
Completed 400 Bad Request in 1ms
ActionController::ParameterMissing - param is missing or the value is empty: song:

RefineryCMS: apply bootstrap styles to navigation menu

I have upgraded Refinery CMS to the newest version (2.1.0), where there is a new approach in rendering the navigation menu :
(in partial _header.html.erb)
<%= Refinery::Pages::MenuPresenter.new(refinery_menu_pages, self).to_html %>
The older version of the same partial :
<%= render(:partial => "/refinery/menu", :locals => {
:dom_id => 'menu',
:css => 'menu'
}) %>
How could I add bootstrap styles to the navbar using MenuPresenter?
It can be done, but the solution is not pretty because the Menu Presenter in Refinery 2.1 doesn't support all the right CSS options out of the box. But with a bit of perseverance, this is roughly what to do:
Firstly, create a new blank file here: config/initializers/refinery/monkey_patch_menu_presenter.rb
In this patch file, paste in the contents of this updated version of the menu presenter (published October 2013): menu_presenter.rb
Next, based on the instructions in section 5 of the menu presenter guide, in your app/helpers/application_helper.rb file, add a new method called navigation_menu:
def navigation_menu
presenter = Refinery::Pages::MenuPresenter.new(refinery_menu_pages, self)
presenter.css = "navbar-inner"
presenter.menu_tag = :div
presenter.list_tag_css = "nav"
presenter.selected_css = "active"
presenter.first_css = ""
presenter.last_css = ""
presenter.max_depth = 0 # prevents dropdown menus, which don't render correctly
presenter
end
Finally, in your app/views/refinery/_header.html.erb file (use $ bundle exec rake refinery:override view=refinery/_header if it doesn't exist), replace the call for:
<%= Refinery::Pages::MenuPresenter.new(refinery_menu_pages, self).to_html %>
with:
<div class="navbar">
<%= navigation_menu.to_html %>
</div>
Ensure that you have the loaded the Bootstrap CSS/JS files and have wrapped the whole page in a <div class="container"> element. Then restart your application for the patch to take affect and hopefully you'll see a familiar bootstrap navigation bar.
Good luck!
Martyn.
Here a version of above menu_presenter.rb that renders sub-menus as well
(This if for Bootstrap 3, RefineryCMS 2.1.1):
require 'active_support/core_ext/string'
require 'active_support/configurable'
require 'action_view/helpers/tag_helper'
require 'action_view/helpers/url_helper'
module Refinery
module Pages
class MenuPresenter
include ActionView::Helpers::TagHelper
include ActionView::Helpers::UrlHelper
include ActiveSupport::Configurable
config_accessor :roots, :menu_tag, :list_tag, :list_item_tag, :css, :dom_id,
:max_depth, :selected_css, :first_css, :last_css, :list_tag_css,
:link_tag_css
self.dom_id = 'menu'
self.css = "collapse navbar-collapse"
self.menu_tag = :div
self.list_tag = :ul
self.list_item_tag = :li
self.selected_css = 'active'
self.first_css = :first
self.last_css = :last
self.list_tag_css = "nav navbar-nav"
def roots
config.roots.presence || collection.roots
end
attr_accessor :context, :collection
delegate :output_buffer, :output_buffer=, :to => :context
def initialize(collection, context)
#collection = collection
#context = context
end
def to_html
render_menu(roots) if roots.present?
end
private
def render_menu(items)
content_tag(menu_tag, :id => dom_id, :class => css) do
render_menu_items(items)
end
end
def render_menu_items(menu_items)
if menu_items.present?
content_tag(list_tag, :class => list_tag_css) do
menu_items.each_with_index.inject(ActiveSupport::SafeBuffer.new) do |buffer, (item, index)|
buffer << render_menu_item(item, index)
end
end
end
end
def render_menu_items_children(menu_items)
if menu_items.present?
content_tag(list_tag, :class => 'dropdown-menu') do
menu_items.each_with_index.inject(ActiveSupport::SafeBuffer.new) do |buffer, (item, index)|
buffer << render_menu_item(item, index)
end
end
end
end
def render_menu_item_link_dropdown(menu_item)
link_to( menu_item.title, context.refinery.url_for(menu_item.url), class: "dropdown-toggle", data: {toggle:"dropdown", target: "#"})
end
def render_menu_item_link(menu_item)
link_to(menu_item.title, context.refinery.url_for(menu_item.url), :class => link_tag_css)
end
def render_menu_item(menu_item, index)
content_tag(list_item_tag, :class => menu_item_css(menu_item, index)) do
buffer = ActiveSupport::SafeBuffer.new
# Check for sub menu
menu_item_children(menu_item).empty? ? buffer << render_menu_item_link(menu_item) : buffer << render_menu_item_link_dropdown(menu_item)
buffer << render_menu_items_children(menu_item_children(menu_item))
buffer
end
end
# Determines whether any item underneath the supplied item is the current item according to rails.
# Just calls selected_item? for each descendant of the supplied item
# unless it first quickly determines that there are no descendants.
def descendant_item_selected?(item)
item.has_children? && item.descendants.any?(&method(:selected_item?))
end
def selected_item_or_descendant_item_selected?(item)
selected_item?(item) || descendant_item_selected?(item)
end
# Determine whether the supplied item is the currently open item according to Refinery.
def selected_item?(item)
path = context.request.path
path = path.force_encoding('utf-8') if path.respond_to?(:force_encoding)
# Ensure we match the path without the locale, if present.
if %r{^/#{::I18n.locale}/} === path
path = path.split(%r{^/#{::I18n.locale}}).last.presence || "/"
end
# First try to match against a "menu match" value, if available.
return true if item.try(:menu_match).present? && path =~ Regexp.new(item.menu_match)
# Find the first url that is a string.
url = [item.url]
url << ['', item.url[:path]].compact.flatten.join('/') if item.url.respond_to?(:keys)
url = url.last.match(%r{^/#{::I18n.locale.to_s}(/.*)}) ? $1 : url.detect{|u| u.is_a?(String)}
# Now use all possible vectors to try to find a valid match
[path, URI.decode(path)].include?(url) || path == "/#{item.original_id}"
end
def menu_item_css(menu_item, index)
css = []
css << selected_css if selected_item_or_descendant_item_selected?(menu_item)
css << "dropdown" unless menu_item_children(menu_item).empty?
css << first_css if index == 0
css << last_css if index == menu_item.shown_siblings.length
css.reject(&:blank?).presence
end
def menu_item_children(menu_item)
within_max_depth?(menu_item) ? menu_item.children : []
end
def within_max_depth?(menu_item)
!max_depth || menu_item.depth < max_depth
end
end
end
end

How can I remove onEvent from button widget in Corona?

I am trying to remove onEvent listener from button widget. I tried to assign nil to onEvent attribute but it didn't work and lastly I tried this:
buttonWidget : removeEventListener("touch", buttonWidget.onEvent)
I have several button like that and it just stopped all button's event listeners. What do you suggest? How can I remove the event listener for one button widget? Thanks.
Here is how I create my button widgets:
for i=0,2 do
for j=0,8 do
count=count+1
letterBtn[count] = widget.newButton{
id = alphabet[count],
left = 5+j*50,
top = H-160+i*50,
label = alphabet[count],
width = 45,
height = 45,
font = nil,
fontSize = 18,
labelColor = { default = {0,0,0}, over = {255,255,255}},
onEvent = btnOnEventHandler
};
end
end
Can you tell me how can I remove onEvent later?
Okey, I tried Button: setEnabled(false) but still it disables all buttons not just one. I already tried your second advice but it gives the same result. I am copying the rest of the code. Can you please look at it and tell me what I am missing?
local function checkLetter(e)
if(guessWord) then
for i=1, #guessWord do
local c = guessWord:sub(i,i)
if c==e.target.id then
letter[i].text = e.target.id
letterCount = letterCount +1
print("letterCount"..letterCount)
e.target:setEnabled(false)
end
end
if (letterCount == #guessWord and not hanged) then
timer.performWithDelay(500, function()
letterCount=0
rightWGuess = rightWGuess+1
for k,v in pairs(notGuessedWord) do
if v == guessWord then
notGuessedWord[k]=nil
end
end
enableButtons()
startGame() end ,1)
end
end
end
local function btnOnEventHandler(e)
if(e.phase == "began") then
checkLetter(e)
print(e.target.id)
end
return true
end
If you want to temporarily (or permanently) stop a button from responding to touch events, you can use Button:setEnabled(false).
The following worked for me for removing a listener from just 2 buttons. Button 1 and 3 stopped responding to events as expected while 2, 4, and 5 still did.
Update: To disable, you have to do it on the 'ended' phase or Corona gets confused.
widget = require 'widget'
local function btnOnEventHandler(event)
print('Event', event.target.id, event.phase)
if event.phase == 'ended' then
-- Disable the button so it can't be clicked again
-- Must disable in the end state or Corona gets
-- confused
event.target:setEnabled(false)
end
end
local buttons = {}
for i=1,5 do
buttons[i] = widget.newButton{
id = 'button' .. i,
left = display.contentCenterX - 50,
top = 60 * i,
label = 'Button ' .. i,
width = 100,
height = 50,
onEvent = btnOnEventHandler
}
end
buttons[1]:removeEventListener('touch', buttons[1].onEvent)
buttons[3]:removeEventListener('touch', buttons[3].onEvent)

Get HTTP response body as string (BubbleWrap for RubyMotion)

Using RubyMotion (for the first time!), I want to use Twitter's search API to retrieve some recent tweets for some users so have put together the class below.
The value of tweets is always an empty array. I suspect that BW::HTTP.get(url) spawns its own thread which is causing the issue.
Really, I just want twitter_search_results to return response.body.to_str but I am not sure how to do this.
How do I use RubyMotion (or BubbleWrap) to put an array of Tweet objects into my UIViewController?
class TweetsController
def initialize
#twitter_accounts = %w(dhh google)
#tweets = []
end
def tweets
twitter_search_results
puts #tweets.count
#tweets
end
def create_tweets(response)
BW::JSON.parse(response)["results"].each do |result|
#tweets << Tweet.new(result)
end
end
def twitter_search_results
query = #twitter_accounts.map{ |account| "from:#{account}" }.join(" OR ")
url = "http://search.twitter.com/search.json?q=#{query}"
BW::HTTP.get(url) do |response|
create_tweets(response.body.to_str)
end
end
end
class TwitterViewController < UIViewController
def viewDidLoad
super
self.view.backgroundColor = UIColor.blueColor
#table = UITableView.alloc.initWithFrame(self.view.bounds)
self.view.addSubview #table
#table.dataSource = self
#tweets_controller = TweetsController.new
end
def initWithNibName(name, bundle: bundle)
super
self.tabBarItem = UITabBarItem.alloc.initWithTitle(
"Twitter",
image: UIImage.imageNamed('twitter.png'),
tag: 1)
self
end
def tableView(tableView, numberOfRowsInSection: section)
#tweets_controller.tweets.length
end
def tableView(tableView, cellForRowAtIndexPath: indexPath)
#reuse_id = "Tweet"
cell = UITableViewCell.alloc.initWithStyle(UITableViewCellStyleDefault, reuseIdentifier:#reuse_id)
cell.textLabel.text = #tweets_controller.tweets[indexPath.row].text
return cell
end
end
class Tweet
attr_reader :created_at, :from_user, :text
def initialize(tweet_result)
#created_at = tweet_result["created_at"]
#from_user = tweet_result["from_user"]
#text = tweet_result["text"]
end
end
Full controller code below. I've also put the project on GitHub
class TweetsController
def initialize
#twitter_accounts = %w(dhh google)
#tweets = []
create_tweets
end
def tweets
#tweets
end
def create_tweets
json_data = twitter_search_results.dataUsingEncoding(NSUTF8StringEncoding)
e = Pointer.new(:object)
dict = NSJSONSerialization.JSONObjectWithData(json_data, options:0, error: e)
dict["results"].each do |result|
p result.class
p result
#tweets << Tweet.new(result)
end
end
def twitter_search_results
query = #twitter_accounts.map{ |account| "from:#{account}" }.join(" OR ")
url_string = "http://search.twitter.com/search.json?q=#{query}"
url_string_escaped = url_string.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
url = NSURL.URLWithString(url_string_escaped)
request = NSURLRequest.requestWithURL(url)
response = nil
error = nil
data = NSURLConnection.sendSynchronousRequest(request, returningResponse: response, error: error)
raise "BOOM!" unless (data.length > 0 && error.nil?)
json = NSString.alloc.initWithData(data, encoding: NSUTF8StringEncoding)
end
end
the issue here is asynchronicity. you're almost there, I think, but the create_tweets method is not called before puts #tweets. In this case, I would recommend using a notification, because I think they are good ;-)
TweetsReady = 'TweetsReady' # constants are nice
NSNotificationCenter.defaultCenter.postNotificationName(TweetsReady, object:#tweets)
In your controller, register for this notification in `viewWillAppear` and unregister in `viewWillDisappear`
NSNotificationCenter.defaultCenter.addObserver(self, selector: 'tweets_ready:', name: TweetsReady, object:nil) # object:nil means 'register for all events, not just ones associated with 'object'
# ...
NSNotificationCenter.defaultCenter.removeObserver(self, name:TweetsReady, object:nil)
and you tweets_ready method should implement your UI changes.
def tweets_ready(notification)
#table.reloadData
end

Resources