Needs redirects for routing - ruby-on-rails-5

I'm very excited about Camaleon cms for rails 5; however, I've noticed a significant problem with posts that have parent slugs or have post-type slugs in the url as a url format.
For background, it's very important that a post's content can only be reached via one single url. Otherwise, you have the potential for getting penalized in google for having duplicate content. For those who rely on search engine traffic (basically everyone who would ever use a CMS), this is a very serious issue.
The following is an example of the issue. All of these urls will render the same post content:
http://www.example.com/parent_slug/post_slug
http://www.example.com/post_slug
http://www.example.com/parent_slug_blah_blah/post_slug
Or
http://www.example.com/post_type/post_slug
http://www.example.com/post_slug
http://www.example.com/post_type_blah_blah/post_slug
The way Wordpress deals with this issue is to redirect to the proper url with the correct parent slug if it doesn't exist or if it is misspelled.
My question here is for those in the know, is this perhaps a priority issue in one of the upcoming releases?

I'm not sure if this will work for everyone, but here's my solution to this issue.
Requirements: this will only work for posts that have the "post_of_posttype", "heirarchy_post" or "post_of_category_post_type" route formats.
The following code is extending the functionality of Camaleon's frontend controller method render_post by simply adding a redirect when the params don't match the #post.the_path. Seems to work for my purposes. Hopefully it will help someone else.
Create a new file in your config/initializers folder and place the following code:
# config/initializers/camaleon_custom_post.rb
CamaleonCms::FrontendController.class_eval do
# render a post
# post_or_slug_or_id: slug_post | id post | post object
# from_url: true/false => true (true, permit eval hooks "on_render_post")
def render_post(post_or_slug_or_id, from_url = false, status = nil)
if post_or_slug_or_id.is_a?(String) # slug
#post = current_site.the_posts.find_by_slug(post_or_slug_or_id)
elsif post_or_slug_or_id.is_a?(Integer) # id
#post = current_site.the_posts.where(id: post_or_slug_or_id).first
else # model
#post = post_or_slug_or_id
end
unless #post.present?
if params[:format] == 'html' || !params[:format].present?
page_not_found()
else
head 404
end
else
#post = #post.decorate
if ["post_of_posttype","hierarchy_post"].include? #post.the_post_type.contents_route_format
if params[:parent_title].nil? && params[:post_type_title].nil?
params_path = "/" + params[:slug]
elsif !params[:parent_title].nil?
params_path = "/" + params[:parent_title] + "/" + params[:slug]
elsif !params[:post_type_title].nil?
params_path = "/" + params[:post_type_title] + "/" + params[:slug]
end
unless (#post.the_path === params_path)
redirect_to #post.the_url, status: 301 and return
end
elsif #post.the_post_type.contents_route_format === "post_of_category_post_type"
if [params[:post_type_title],params[:label_cat],params[:category_id],params[:title]].all?
params_path = [params[:post_type_title],params[:label_cat],params[:category_id] + "-" + params[:title],params[:slug]].join("/")
params_path.prepend("/")
unless (#post.the_path === params_path)
redirect_to #post.the_url, status: 301 and return
end
else
redirect_to #post.the_url, status: 301 and return
end
end
#object = #post
#cama_visited_post = #post
#post_type = #post.the_post_type
#comments = #post.the_comments
#categories = #post.the_categories
#post.increment_visits!
# todo: can_visit? if not redirect home page
home_page = #_site_options[:home_page] rescue nil
if lookup_context.template_exists?("page_#{#post.id}")
r_file = "page_#{#post.id}"
elsif #post.get_template(#post_type).present? && lookup_context.template_exists?(#post.get_template(#post_type))
r_file = #post.get_template(#post_type)
elsif home_page.present? && #post.id.to_s == home_page
r_file = "index"
elsif lookup_context.template_exists?("post_types/#{#post_type.the_slug}/single")
r_file = "post_types/#{#post_type.the_slug}/single"
elsif lookup_context.template_exists?("#{#post_type.slug}")
r_file = "#{#post_type.slug}"
else
r_file = "single"
end
layout_ = nil
meta_layout = #post.get_layout(#post_type)
layout_ = meta_layout if meta_layout.present? && lookup_context.template_exists?("layouts/#{meta_layout}")
r = {post: #post, post_type: #post_type, layout: layout_, render: r_file}
hooks_run("on_render_post", r) if from_url
if status.present?
render r[:render], (!r[:layout].nil? ? {layout: r[:layout], status: status} : {status: status})
else
render r[:render], (!r[:layout].nil? ? {layout: r[:layout]} : {})
end
end
end
end
Seems kind of strange the mandatory redirect for non-accurate urls is not in the core camaleon application, but perhaps most people who use this cms are creating internally facing apps. Anyway, if that's not the case, I think this should be a priority fix.

Related

NameError (uninitialized constant Twitter::TextExtractor):

I am getting error while using Twitter-text gem.
I am getting -> NameError (uninitialized constant Twitter::TextExtractor) while creating entry.
here is the right code below
class EntryParser
class << self
include Twitter::Extractor
# Default CSS class for auto-linked lists
DEFAULT_LIST_CLASS = "url link-list-slug".freeze
# Default CSS class for auto-linked usernames
DEFAULT_USERNAME_CLASS = "url link-username".freeze
# Default CSS class for auto-linked hashtags
DEFAULT_HASHTAG_CLASS = "url link-hashtag".freeze
# Default CSS class for auto-linked cashtags
DEFAULT_CASHTAG_CLASS = "url link-cashtag".freeze
# Default URL base for auto-linked usernames
DEFAULT_USERNAME_URL_BASE = "/users/".freeze
# Default URL base for auto-linked lists
DEFAULT_LIST_URL_BASE = "/users".freeze
# Default URL base for auto-linked hashtags
DEFAULT_HASHTAG_URL_BASE = "/tags/".freeze
# Default URL base for auto-linked cashtags
DEFAULT_CASHTAG_URL_BASE = "#!tag?q=%24".freeze
# Default attributes for invisible span tag
DEFAULT_INVISIBLE_TAG_ATTRS = "style='position:absolute;left:-9999px;'".freeze
DEFAULT_OPTIONS = {
:list_class => DEFAULT_LIST_CLASS,
:username_class => DEFAULT_USERNAME_CLASS,
:hashtag_class => DEFAULT_HASHTAG_CLASS,
:cashtag_class => DEFAULT_CASHTAG_CLASS,
:username_url_base => DEFAULT_USERNAME_URL_BASE,
:list_url_base => DEFAULT_LIST_URL_BASE,
:hashtag_url_base => DEFAULT_HASHTAG_URL_BASE,
:cashtag_url_base => DEFAULT_CASHTAG_URL_BASE,
:invisible_tag_attrs => DEFAULT_INVISIBLE_TAG_ATTRS
}.freeze
def parse(entry)
sanitizer = Rails::Html::FullSanitizer.new
sanitized = sanitizer.sanitize(entry.body.gsub(/^(\[[\sx]*)\]/, ''))
sanitized.gsub("\n", "<br/>")
end
# Produces an HTML output string with all of the parsed links we want
def auto_link(entry)
parsed = parse(entry)
entities = extract_entities(parsed)
auto_link_entities_wthout_cmmnt(entry, parsed, entities)
end
def auto_link_comment(reaction) # should probably live in a CommentParser
# This will break if we allow comments on comments, then we need to rethink how
# we do this
if reaction.reaction_type == 'comment' && reaction.reactable.class == Entry
sanitizer = Rails::Html::FullSanitizer.new
sanitized = sanitizer.sanitize(reaction.body)
entities = extract_entities(sanitized)
auto_link_entities(reaction.reactable, reaction, sanitized, entities)
else
reaction.body
end
end
def auto_link_entities_wthout_cmmnt(entry, text, entities)
return text if entities.empty?
# TODO: This is likely inefficient, needs caching or preloading
if entry.team.personal?
org_hash = nil
personal = true
else
org_hash = entry.team.organization.hash_id
personal = false
end
Twitter::Rewriter.rewrite_entities(text.dup, entities) do |entity, _chars|
if entity[:url]
image_or_link(entity[:url])
elsif entity[:hashtag]
if personal
"##{entity[:hashtag]}"
else
"##{entity[:hashtag]}"
end
elsif entity[:screen_name]
if !personal && user = entry.team.active_users.where(go_by_name: entity[:screen_name]).first
"##{entity[:screen_name]}"
else
"##{entity[:screen_name]}"
end
end
end
end
def auto_link_entities(entry,comment , text, entities)
return text if entities.empty?
# TODO: This is likely inefficient, needs caching or preloading
if entry.team.personal?
org_hash = nil
personal = true
else
org_hash = entry.team.organization.hash_id
personal = false
end
Twitter::Rewriter.rewrite_entities(text.dup, entities) do |entity, _chars|
if entity[:url]
image_or_link(entity[:url])
elsif entity[:hashtag]
if personal
"##{entity[:hashtag]}"
else
if comment
"##{entity[:hashtag]}"
else
"##{entity[:hashtag]}"
end
end
elsif entity[:screen_name]
if !personal && user = entry.team.active_users.where(go_by_name: entity[:screen_name]).first
"##{entity[:screen_name]}"
else
"##{entity[:screen_name]}"
end
end
end
end
# This is overridden from Twitter::Extractor because we don't want cashtags
def extract_entities(text, &block)
entities = extract_urls_with_indices(text, {extract_url_without_protocol: true}) +
extract_hashtags_with_indices(text, :check_url_overlap => false) +
extract_mentions_or_lists_with_indices(text)
return [] if entities.empty?
entities = remove_overlapping_entities(entities)
entities.each(&block) if block_given?
entities
end
def image_or_link(entity_link)
entity_url = entity_link.length > 30 ? "#{entity_link[0,25]}..." : entity_link
page_path = Addressable::URI.heuristic_parse(entity_link).to_s
begin
if ['.jpg','.png', '.gif', '.jpeg'].any? { |image_ext| page_path.downcase.include?(image_ext) }
"#{entity_url}
<div class='entry-img'>
<img src='#{page_path}' style='max-width:266px; max-height:200px;'>
</div>"
else
"#{entity_url}"
end
rescue
"#{entity_url}"
end
end
end
end
I don't know what is problem here.

Undefined method to_slug in Page controller

I cant understand my this is not working. I am trying to add a method to create a slug from the title of a page when the user creates a new page (using Ruby on Rails).
This is my create method:
def create
#page = Page.new(params[:page])
#page.user_id = current_user.id
#page.slug = #page.title.to_slug
respond_to do |format|
if #page.save
format.html { redirect_to #page, notice: 'Page was successfully created.' }
format.json { render json: #page, status: :created, location: #page }
else
format.html { render action: "new" }
format.json { render json: #page.errors, status: :unprocessable_entity }
end
end
end
Adn this is my method at the bottom of the same same controller. (pages_controller.rb) :
def to_slug(param=self.slug)
# strip the string
ret = param.strip
#blow away apostrophes
ret.gsub! /['`]/, ""
# # --> at, and & --> and
ret.gsub! /\s*#\s*/, " at "
ret.gsub! /\s*&\s*/, " and "
# replace all non alphanumeric, periods with dash
ret.gsub! /\s*[^A-Za-z0-9\.]\s*/, '-'
# replace underscore with dash
ret.gsub! /[-_]{2,}/, '-'
# convert double dashes to single
ret.gsub! /-+/, "-"
# strip off leading/trailing dash
ret.gsub! /\A[-\.]+|[-\.]+\z/, ""
ret
end
The slug method is from this question:
Best way to generate slugs (human-readable IDs) in Rails
I cant understand why this creates a method undefined error or how to fix it. Any help, hint or answer is appreciated. :)
The to_slug method is an instance method of PagesController class. The object #page.title don't have this method, that's the reason why the code not working.
There are several ways to make the method to_slug work, such as helper, decorate. But I think the best way is to put such logic into model, because slug is actually part of the model. We'll make slug attribute available instantly before saving(create and update).
So, in Page model. Assume you already have slug attribute.
Step 1: Setup callback
before_saving :update_slug # for create record, before actual saving
Step 2: update_slug method
def update_slug
ret = self.title # Use title variable directly
# .... You to_slug code. Almost same.
self.slug = ret # return slug
end
The above are basic ideas to provide a thought, not verified yet. Please check and verify it by yourself. Hope that helps.

How to stop a helper method from applying to a specific controller?

I have a helper_method that allows links to escape from a subdomain. However it is impacting my videos_controller, as it essentially seems to negate the 'current_event' method when not in the events controlller.
I've tried several dozen different ways over the last 4 days to make it so I can still escape my links from the subdomain, but still allow the videos_controller to work.
I think the best way to achieve this is to exclude the videos_controller from the helper method, but I'm not sure how (or if it is actually the best way forward - I'm obviously a noob!) Any suggestions please?! Relevant code below:
module UrlHelper
def url_for(options = nil)
if request.subdomain.present? and request.subdomain.downcase != 'www' and !options.nil? and options.is_a?(Hash) and options.has_key? :only_path and options[:only_path]
options[:only_path] = false
end
super
end
end
Videos_controller
def new
if current_event?
#video = current_event.videos.new
else
#video = Video.new
end
end
def create
if current_event.present?
#video = current_event.videos.new(params[:video])
#video.user_id = current_user.id
key = get_key_from_the_cloud
#video.key = key
else
#video = current_user.videos.new(params[:video])
#video.user_id = current_user.id
key = get_key_from_the_cloud
#video.key = key
end
if #video.save
flash[:success] = "Video uploaded!"
redirect_to root_url(subdomain: => current_event.name)
else
flash[:error] = "#{#video.errors.messages}"
render :new
end
end
current_event method
def current_event
if request.subdomain.present?
#event = Event.find_by_name(request.subdomain)
end
end
Did you take a look at this post yet?
You might want to create a new function test that only does something like
module UrlHelper
def test
puts "Test is called"
end
end
If that works you know its not including that fails but it has to be the method.
Otherwise you know the module is not included and you can narrow down the search.

Why is my Rails model custom setter/getter method failing?

what am I doing wrong here?
I have a model for an app I am writing called page. Those attributes are:
title
pagetype
page_url
title and pagetype can be set as normally, but I used a custom getter/setter for the page_url. Here is the logic/model:
class Page < ActiveRecord::Base
def page_url=()
temp = self[:title]
pageUrl = temp.gsub(" ", "_").downcase
if self[:pagetype] == "home"
pageUrl = "/"
end
self[:page_url] = pageUrl
end
def page_url
self[:page_url]
end
end
It's fairly simple -> page_url is based on the title with all spaces replaced with unless page_type == "home", which then gets set to "/". For the record I don't want to make page_url virtual because I need it to be searchable and saved in the db.
So unfortunately whether in rails console or my app this is failing. Here is how I am calling the setter method in the console;
page1 = Page.new
page1.pagetype = "home"
page1.title = "this is a test"
page2 = Page.new
pager2.pagetype = "content"
page2.title = "this is another test"
#expected results should be
page1.page_url()
=> "/"
page2.page_url()
However I keep getting this:
page1.page_url()
=> nil
What the heck am I doing wrong here?
These custom setter and getters don't persist to the database. If you have a column page_url in your database, you can set the value with a callback. E.g. before_save:
class Page < ActiveRecord::Base
before_save :set_page_url
def set_page_url
if self[:pagetype] == "home"
self.page_url = "/"
else
self.page_url = self[:title].gsub(" ", "_").downcase
end
end
end

Undefined Method `authorize_from_request' using OAuth and Twitter Gem in Ruby on Rails 3

Im getting the following error:
undefined method `authorize_from_request'
Based on the documenation here: http://oauth.rubyforge.org/rdoc/classes/OAuth/Consumer.html
That method doesnt exist, but I saw this method used here:
http://teachmetocode.com/screencasts/oauth-with-the-twitter-gem/ and
so I'm guessing it was deprecated some time ago, but I can't seem to
find its replacement and was wondering what other way could I go about
solving this issue?
Thanks in Advance!
Controller Code:
class TwitterController < ApplicationController
def index
end
def login
oauth_request_token = oauth.get_request_token(:oauth_callback => "http://gnome.local/twitter/finalize")
session[:request_token] = oauth_request_token.token
session[:request_secret] = oauth_request_token.secret
redirect_url = oauth_request_token.authorize_url
redirect_url = "http://" + redirect_url unless redirect_url.match(/^http:\/\//)
redirect_to redirect_url
end
def finalize
oauth.authorize_from_request(session[:request_token], session[:request_secret], params[:oauth_verifier])
#client = Twitter::Client.new(oauth).verify_credentials
session[:request_token] = nil
session[:request_secret] = nil
oauth_access_token = oauth.get_access_token
#oauth_token = session[:oauth_token] = oauth_access_token.token
session[:oauth_secret] = oauth_access_token.secret
end
def client
oauth.authorize_from_access(session[:auth_token])
end
def oauth
#oauth ||= OAuth::Consumer.new(APP_CONFIG[:twitter][:consumer_key], APP_CONFIG[:twitter][:consumer_secret], :site => "http://api.twitter.com", :request_endpoint => "http://api.twitter.com", :sign_in => true);
end
end
(Original Post: http://groups.google.com/group/oauth-ruby/browse_thread/thread/614b27e4f5d80fab)
Got the same problem, the solution is to use according to the (old) Twitter gem:
request_token.get_access_token(oauth_verifier: params[:oauth_verifier])