I am trying to use relative_url filter inside a plugin.
module Jekyll
module Tags
class MyNewTag < Liquid::Block
include Jekyll::Filters::URLFilters
def initialize(tag_name, block_options, liquid_options)
super
#class = block_options.strip
end
def render(context)
context.stack do
context["class"] = #class
#content = super
path_js = Jekyll::Filters::URLFilters::relative_url("assets/custom.min.css")
path_css = Jekyll::Filters::URLFilters::relative_url("assets/custom.min.js")
end
output = <<~EOS
<link rel="stylesheet" href="#{path_js}">
<script src="#{path_css}"></script>
EOS
end
end
end
end
Liquid::Template.register_tag('MyNewTag', Jekyll::Tags::MyNewTag)
However, Ruby shows NoMethodError: undefined method relative_url' for Jekyll::Filters::URLFilters:Module` - hence I am not able to use it.
How should I include relative_url filter, so that I could use it in my code?
It turns out, that the error was caused by the lack of context variable, which must be passed explicitly by #context = context
It works, if it is formatted this way:
module Jekyll
module Tags
class MyNewTag < Liquid::Block
include Jekyll::Filters::URLFilters
def initialize(tag_name, block_options, liquid_options)
super
#class = block_options.strip
end
def render(context)
context.stack do
context["class"] = #class
#content = super
#context = context
#path_js = relative_url("assets/custom.min.css")
#path_css = relative_url("assets/custom.min.js")
end
output = <<~EOS
<link rel="stylesheet" href="#{#path_js}">
<script src="#{#path_css}"></script>
EOS
end
end
end
end
Liquid::Template.register_tag('MyNewTag', Jekyll::Tags::MyNewTag)
Related
I'm trying to learn about services in Rails in order to avoid fat controllers.
Here a tried a simple product review creation
class ProductReviewsController < ApplicationController
before_action :set_product, only: :create
def new
#product_review = ProductReview.new
#product = Product.find(params[:product_id]) end
def create
if AddReviewService.call(product_review_params, #product)
redirect_to product_path(#product)
else
render :new
end
end
private
def set_product
#product = Product.find(params[:product_id]) end
def product_review_params
params.require(:product_review).permit(:content, :rating) end end
The thing is that in the case of wrong parameters for the review the render :new generates the following error :
screenshot of error received
Showing /home/miklw/code/michaelwautier/multitenant_app/app/views/product_reviews/new.html.erb where line #3 raised:
undefined method 'model_name' for nil:NilClass
Extracted source (around line #3):
1 <h1>New review for <%= #product.name %></h1>
2
3 <%= simple_form_for [#product, #product_review] do |f| %>
4 <%= f.input :content %>
5 <%= f.input :rating %>
6 <%= f.button :submit %>
Rails.root: /home/miklw/code/michaelwautier/multitenant_app
Application Trace | Framework Trace | Full Trace
app/views/product_reviews/new.html.erb:3:in `_app_views_product_reviews_new_html_erb__802305224391576972_70155240081100'
app/controllers/product_reviews_controller.rb:14:in `create'
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"Z7YeYvXKKr7uYhANlevZ4H8U00p9givKzXzfue4pNFk0jE2DtTNY7Eacqati+V8IihSofLc2WPa4ZBzR2o0v5w==",
"product_review"=>{"content"=>"te", "rating"=>"9"},
"commit"=>"Create Product review",
"product_id"=>"4"}
Toggle session dump
Toggle env dump
Response
Headers:
None
In the error page console, if I type #product, I get the expected product object, but #product_review is nil.
BUT, if I use the regular way (see below), the form gets re-render as it should, with the notice message of the form
class ProductReviewsController < ApplicationController
before_action :set_product, only: :create
def new
#product_review = ProductReview.new
#product = Product.find(params[:product_id])
end
def create
#product_review = ProductReview.new(product_review_params)
#product_review.product = #product
if #product_review.save
redirect_to product_path(#product)
else
render :new
end
end
private
def set_product
#product = Product.find(params[:product_id])
end
def product_review_params
params.require(:product_review).permit(:content, :rating)
end
end
Any idea what could cause this issue ?
EDIT : Here is the service I call :
class AddReviewService < ApplicationService
attr_reader :content, :rating
def initialize(params, product)
#content = params[:content]
#rating = params[:rating]
#product = product
end
def call
review = ProductReview.new(content: #content, rating: #rating)
review.product = #product
return true if review.save
return false
end
end
EDIT 2 : returning the review when saved
def call
review = ProductReview.new(content: #content, rating: #rating)
review.product = #product
return review if review.save
return false
end
I'm working on a shopping cart in Ruby Sinatra (TDD'd with Rspec and Capybara) and don't understand how to make the "Buy" button add an item to the cart.
Looking for some help understanding my problem and advice on refactoring, as I'm sure at this stage I'm making lots of dreadful mistakes.
What I think are the relevant parts:
View:
<% #products.each do |product| %>
<h3><div class="productName">
<%= product["name"] %>
</div></h3>
<% if product["stock"] > 0 %>
<form action="/" method="POST">
<button type="submit" name="item" class="buyButton">Buy</button>
</form>
<% else %>
<button value="Sold out" class="soldOutButton" disabled>Sold out</button>
<% end %>
<% end %>
Controller:
class RubyShop
shop = Shop.new
before do
#products ||= shop.products
#cart ||= shop.cart
end
get "/" do
session[:item] = params["item"]
#cart.add(session[:item])
erb :products
end
post "/" do
session[:item] = params["item"]
#cart.add(session[:item])
erb :products
end
end
Models:
# shop.rb
require "json"
require_relative "cart"
class Shop
attr_reader :products, :cart
def initialize options = { products: "products.json" }
file = File.read options[:products]
#products = JSON.parse file
#cart = Cart.new
end
end
class Cart
attr_reader :products
def initialize
#products = []
end
def add item
return nil unless item
add_quantity_value_to_hash item
cart_contains_item?(item) ? increment_quantity(item) : add_product(item)
end
def add_quantity_value_to_hash item
item["quantity"] ||= 1
end
def cart_contains_item? item
#products.include? item
end
def increment_quantity item
#products.find do |product|
product["quantity"] += 1 if product["name"] == item["name"]
end
end
def add_product item
#products << item
end
def total
#products.inject(0) do |sum, product|
sum + (product["price"] * product["quantity"])
end
end
end
Sample JSON fixture:
[ { "name": "Black trainers",
"category": "Footwear",
"image": "http://www.img.com/1.jpg",
"price": 100.00,
"stock": 99 } ]
When click on "Buy" I get this error:
IndexError at /
string not matched
file: cart.rb location: []= line: 15
And my Rspec tests give me this error:
IndexError:
string not matched
I've searched for the error on the web but not found a solution.
I need to call method download_images("\folder","http:\url") which save pictures from url in choosen directory.This method should be called in index.html.erb and grab folder address from textbox1 and url from textbox2 after pressing the button1.
Right now I don't know how to grab strings from textboxes, I am trying to call method correctlyThe index.html.erb code:
<h1>Welcome#index</h1>
<p><%= "Download pictures from url!" %></p>
<div class="form-horizontal">
<p> Input url: </p>
<p> <input type="text"/> </p>
<p> Input destination folder: </p>
<p> <input type="text"/> </p>
<button class="btn">Go!</button>
<% button_to "btn", :method=> download_images("`/tutorial1/downloadedpics","http://www.yandex.ru/") %>
</div>
I defined method download_images in welcome_controller.rb:
class WelcomeController < ApplicationController
def index
end
def download_images(url, destination_path, options = {})
base_url = URI.join(url, "/").to_s
body = Typhoeus::Request.get(url).body
imgs = Nokogiri::HTML(body).css("img")
image_srcs = imgs.map { |img| img["src"] }.compact.uniq
hydra = Typhoeus::Hydra.new(:max_concurrency => options[:max_concurrency] || 50)
image_paths = image_srcs.map do |image_src|
image_url = URI.join(base_url, image_src).to_s
path = File.join(destination_path, File.basename(image_url))
request = Typhoeus::Request.new(image_url)
request.on_complete { |response| File.write(path, response.body) }
hydra.queue(request)
path
end
hydra.run
image_paths
end
end
After I switch server and go to localhost, I receive an exception:
NoMethodError in Welcome#index, undefined method download_images' for #<#<Class:0x007f202fc3ae50>:0x007f202f9ab518>, in line <% button_to "btn", :method=> download_images("/tutorial1/downloadedpics","http://www.yandex.ru/") %>
I am a noob programmer, so I can do rather dumb mistakes...
And it is important to mention: I work in Nitrous web box, and don't really know is it possible to download images in box folder:
~/tutorial1/downloadedpics
Also I use Bootstrap controllers,Nokogiri gem and Typhoeus gem.
Ruby version:ruby 2.1.1p76
Rails version:Rails 4.1.0
Thank you for your attention.
As a FYI, doing:
imgs = Nokogiri::HTML(body).css("img")
image_srcs = imgs.map { |img| img["src"] }.compact.uniq
is not the right way to find images with "src" parameters. Because you're not searching correctly, you get nils in your resulting array, forcing you to use compact. Instead, don't rely on cleaning up after making a mess, just avoid making the mess in the first place:
require 'nokogiri'
body = <<EOT
<html>
<body>
<img>
<img src="foo">
</body>
</html>
EOT
imgs = Nokogiri::HTML(body).css("img[#src]")
image_srcs = imgs.map { |img| img["src"] }
image_srcs # => ["foo"]
This config.rb works:
helpers do
def link_to_nothing(text)
link_to(text, "#")
end
end
With template index.html.erb:
<%= link_to_nothing "Test link" %>
But when I try to add a method to the Middleman::Sitemap::Resource class in this config.rb:
helpers do
class Middleman::Sitemap::Resource
def link(text)
link_to(text, path)
end
end
end
With template index.html.erb:
<%= current_page.link "This page" %>
The following error comes up when loading the page:
NoMethodError at /index.html
undefined method `link_to' for #<Middleman::Sitemap::Resource:0x3139848>
I've found that link_to is an instance method of class Middleman::Application, which I can access through the app variable:
helpers do
class Middleman::Sitemap::Resource
def link(text)
app.link_to(text, path)
end
end
end
I have just managed to get Konacha running for my client side integration tests.
Konacha runs the ember application in an iframe for testing. In my app, I create img elements programmatically based on user actions. When I set the 'src' attribute the resulting url that is used to fetch the image file from the server has the '/iframe' part added to it like so:
http://0.0.0.0:3500/iframe/assets/regensberg/regensberg_1.jpg
Which gives a 404 (Not Found)
The code does run correctly when I serve it from a regular rails development server
rails s
The correct url should read:
http://0.0.0.0:3500/assets/regensberg/regensberg_1.jpg
Any ideas why it is doing this an how to get around it?
* Edit *
Looking into the Konacha code I find the routes defined in konacha/config/routes.rb
Konacha::Engine.routes.draw do
get '/iframe/*name' => 'specs#iframe', :format => false, :as => :iframe
root :to => 'specs#parent'
get '*path' => 'specs#parent', :format => false
end
We see that this request gets passed to the iframe method in the specs controller.
konacha/app/controllers/konacha/specs_ controller.rb shows us where the 404 message comes from.
module Konacha
class SpecsController < ActionController::Base
rescue_from Konacha::Spec::NotFound do
render :text => "Not found", :status => 404
end
def parent
#run_mode = params.fetch(:mode, Konacha.mode).to_s.inquiry
#specs = Konacha::Spec.all(params[:path])
end
def iframe
#spec = Konacha::Spec.find_by_name(params[:name])
#stylesheets = Konacha::Engine.config.konacha.stylesheets
end
end
end
Looking into the model, we see where the Spec::NotFound comes from:
module Konacha
class Spec
class NotFound < StandardError
end
def self.all(path = nil)
paths = Konacha.spec_paths
paths = ENV["SPEC"].split(",") if ENV["SPEC"]
paths = paths.map { |p| new(p) }
if path.present?
paths = paths.select { |s| s.path.starts_with?(path) }.presence or raise NotFound
end
paths
end
def self.find_by_name(name)
all.find { |s| s.asset_name == name } or raise NotFound
end
attr_accessor :path
def initialize(path)
#path = path
end
def asset_name
path.sub(/(\.js|\.coffee).*/, '')
end
end
end
With the above info, we see why we get the error message instead of the image file when we send the get request to the path that includes 'iframe'. So, why does the URL include 'iframe'?
Looking into the parent view code:
<!doctype html>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>Konacha Tests</title>
<%= stylesheet_link_tag "konacha", :debug => false %>
<%= javascript_include_tag "mocha", "konacha/parent", :debug => false %>
<%= javascript_include_tag("konacha/runner", :debug => false) if #run_mode.runner? %>
</head>
<body>
<% #specs.each do |spec| %>
<%= content_tag :iframe, "", :src => iframe_path(spec.asset_name), :class => "test-context", "data-path" => spec.path %>
<% end %>
<div id="mocha"></div>
</body>
</html>
we see that the src for the iframe is the iframe path, which from the route above should be:
0.0.0.0:3500/iframe/#{spec.assetName}
I set the img src paramter like this:
img.src = "assets/" + filename
the browser prepends "0.0.0.0:3500/iframe/" to this before making the request. This seems to be causing the real trouble. How to prevent the iframe from including this part in the base URL?
* Finish Edit *
By the way, can someone with a high-enough karma(>1500) create a Konacha tag?
assets/dir/filename.jpg is a relative path; it is interpreted relative to the base URL of the page, which is http://0.0.0.0:3500/iframe/, producing http://0.0.0.0:3500/iframe/assets/dir/filename.jpg. You'll want to use the absolute path /assets/dir/filename.jpg instead, with a leading slash.