I'm writing a ruby-on-rails library module:
module Facets
class Facet
attr_accessor :name, :display_name, :category, :group, :special
...
URI = {:controller => 'wiki', :action => 'plants'}
SEARCH = {:status => WikiLink::CURRENT}
#Parameters is an hash of {:field => "1"} values
def render_for_search(parameters)
result = link_to(display_name, URI.merge(parameters).merge({name => "1"}))
count = WikiPlant.count(:conditions => (SEARCH.merge(parameters.merge({name => "1"}))))
result << "(#{count})"
end
end
...
end
when I call render_for_search I get the error
undefined method 'link_to'
I've tried requiring url_helper directly but can't figure out what's going wrong.
Try this:
ActionController::Base.helpers.link_to
This is because, ActionView urlhelpers are only available to the Views, not in your lib directory.
the link_to method is found in the ActionView::Helpers::UrlHelper module, plus you wou
so try this.
class Facet
include ActionView::Helpers::UrlHelper
...
end
Simply including the helper doesn't get you much further. The helpers assume that they are in the context of a request, so that they can read out the domain name and so on.
Do it the other way around; include your modules in the application helper, or something like that.
# lib/my_custom_helper.rb
module MyCustomHelper
def do_stuff
# use link_to and so on
end
end
# app/helpers/application_helper.rb
module ApplicationHelper
include MyCustomHelper
end
Related
I have a form to edit a page, while it tells it's not a variable from what I have known from related questions. In view, an error is raised from this line:
<%= form_for #wiki, :url => giki_path(#wiki.name), :html => { :method => :put } do |f| %>
Where the #wiki does seem to be an instance, which can be confirmed by:
$ rails console
> #wiki
#<Gollum::Page:70026260995800 Home (markdown) #wiki="path/to/git/wiki/.git">
> #wiki.name
"/wiki/Home"
So I don't understand what is causing the problem:
undefined method `model_name' for #<Gollum::Page:0x007f6084d2bdb0>
Edit:
In controller:
# giki_controller.rb
def edit
#wiki = Wiki.find(params[:id])
end
# the same method, worked fine
def show
#wiki = Wiki.find(params[:id])
end
In model:
# wiki.rb
class Wiki
include ActiveModel::AttributeMethods
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :name, :raw_data, :formatted_data, :title, :path, :change_desc, :versions
# Gollum Init
WIKI = Gollum::Wiki.new(Settings.wiki_repo, :base_path => "/wiki")
# initialize
def initialize(attributes = {})
attributes.each do |key, value|
send("#{key}=", value)
end
end
# no database
def persisted?
false
end
def self.find(name)
WIKI.page(name) # find a page by name
end
First lines from logger:
NoMethodError - undefined method `model_name' for #<Gollum::Page:0x007f607dfec4e8>:
actionpack (4.2.6) lib/action_controller/model_naming.rb:9:in `model_name_from_record_or_class'
actionview (4.2.6) lib/action_view/record_identifier.rb:47:in `dom_class'
Full traceback: I created a gist.
Your backtrace says that model_name is undefined in <Gollum::Page:0x007f607dfec4e8> which is an instance of Gollum::Page.
Reason
form_for method internally calls model_name method. This is actually a valid method name in ActiveRecord's instance.
Try
User.first.model_name
This model_name is not present in #wiki since this is not an instance of Wiki its rather the instance of Gollum::Page.
How can I say that?
Well, I saw you have overridden the self.find method in Wiki
def self.find(name)
WIKI.page(name) # find a page by name
end
so in your edit action, you have used find method to get the persisted instance, which will hand you over an instance Gollum::Page and this is not expected by form_for helper method.
Solution (Edited)
Well, if you were using ActiveRecord and wanted to continue the overridden self.find method then you can use where or find_by_x method instead in edit action. Like
def edit
#wiki = Wiki.find_by_id(params[:id])
end
But looks like you are not using ActiveRecord or your model is not derived from it, so you have to use the form_for method in different fashion.
If you don't need to attach a form to a model instance, then check out ActionView::Helpers::FormTagHelper#form_tag.
form_tag(giki_path(#wiki.name), method: :put)
I use the globalize gem to translate content in my Rails App. Everything works fine when I change the language from the default language :en to :de but when I want to change the language from :de to :en I get a NoMethodError (undefined method 'color' for nil:NilClass)
I did some research and tried a few approches but have to admit I don't completely understand this bit which is probably the reason for the error:
application_controller.rb
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
request.subdomain
request.env["HTTP_ACCEPT_LANGUAGE"]
request.remote_ip
end
def default_url_options(options = {})
(I18n.locale.to_sym.eql?(I18n.default_locale.to_sym) ? {} : {locale: I18n.locale})
end
I would highly appreciate a hint how to solve the problem or some explanation how this code works would be very welcome.
Here's the model:
page.rb
class Page < ActiveRecord::Base
translates :name, :permalink
validates_uniqueness_of :permalink, :message => "This url is already taken"
validates_presence_of :permalink
validates_presence_of :name
validates_format_of :permalink, :with => /\A[a-zA-Z0-9-_]*\z/i, :message => 'Url can only contain downcase letters from a-z and numbers from 0-9 and a dash and underscore'
before_save :only_allow_one_home_page
belongs_to :label
has_many :chapters
accepts_nested_attributes_for :chapters, :allow_destroy => true
mount_uploader :backgroundimage, BackgroundimageUploader
def chapters_for_form
collection = chapters.where(page_id: id)
collection.any? ? collection : chapters.build
end
def to_param
permalink
end
end
And the Controller:
pages_controller.rb
def set_page
#page = Page.find_by_permalink(params[:id])
end
And the routes:
resources :labels, do
resources :pages
end
Try changing your link_to the following:
<%= link_to 'E', params.merge(locale: "en") %>
A bit of explanation:
# You must have `before_action :set_locale` somewhere in your controllers
# So, this method is called before your controller code does its job
def set_locale
# This just sets current locale to params[:locale]
# So when you request URL like http://example.org/controller/action?locale=de,
# params[:locale] contains 'de'
I18n.locale = params[:locale] || I18n.default_locale
end
# default_url_options is function which, well, adds default options
# to every call of url_for helper method
# It is also called internally when you build paths and urls for
# resources, like 'labels_path' or 'pages_url'
def default_url_options(options = {})
# This line just says to add 'locale=...' parameter (locale: I18n.locale) to the request,
# unless default locale is selected
# This will preserve your locale between requests
(I18n.locale.to_sym.eql?(I18n.default_locale.to_sym) ? {} : {locale: I18n.locale})
end
Now, returning to the error. You must provide URL params to your link_to helper. You provide only 'locale', but it should somehow determine which page you want the link to be pointing to. By adding params.merge(locale: en) we instruct it to use current parameters (so it will link to current page), only additionally add locale parameter to it.
My objective is to dynamically load a set of methods to an ActiveRecord model instance based on an attribute that's set:
class Book < ActiveRecord::Base
after_initialize do |cp|
self.class.include "#{cp.subject}".constantize
end
end
I then have the following concerns:
module Ruby
extend ActiveSupport::Concern
def get_framework
'rails'
end
end
module Python
extend ActiveSupport::Concern
def get_framework
'django'
end
end
Then, when I run these separately, I get the correct framework string:
python_book = Book.create(:subject => 'python', :id => 1)
python_book.get_framework -> 'django'
ruby_book = Book.create(:subject => 'ruby', :id => 2)
ruby_book.get_framework -> 'rails'
My problem is that when I have both of the books returned in a query, the Concern is included is the last in the result set and is not picking up the correct Concern methods.
Books.all.order(:id => 'asc').collect do |book|
puts book.get_framework
end
# Result
['rails', 'rails']
I am assuming that this is because the 'include' is happening at the class level and not the instance level. Would love some help as to how to clean this up and make this work.
Use .extend
to add instance methods to a instances of Book instead.
Extends in action:
module Greeter
def say_hello
"Hello"
end
end
irb(main):008:0> a = Object.new
=> #<Object:0x00000101e01c38>
irb(main):009:0> a.extend(Greeter)
=> #<Object:0x00000101e01c38>
irb(main):010:0> a.say_hello
=> "Hello"
irb(main):011:0> Object.new.say_hello
NoMethodError: undefined method `say_hello' for #<Object:0x00000101e196d0>
class Book < ActiveRecord::Base
after_initialize do |cp|
self.extend subject.constantize
end
end
I am using Mongoid(3.0.23) and I want to add nicer URL's, I have followed this rails cast but for some reason my site throws an undefined error for the find_by_slug method. I have read about some gems I could use but it seems pointless for such a simple task.
Model
validates :slug, :uniqueness => true
before_validation :generate_url
def generate_url
self.slug ||= self.title.parameterize if slug.blank?
end
def to_param
slug
end
field :slug
View
<% #events.each do |e| %>
<%= link_to e.title, event_path(e) %>
<% end %>
Controller
def show
#event = Event.find_by_slug!(params[:id])
end
Maybe try:
Event.find_by(slug: params[:id])
Also, not sure if it's necessary but you could specify the type:
field :slug, type: String
Mongoid defines the attribute finder, but not the bang version.
Event.find_by_slug(params[:id])
# => valid
Event.find_by_slug!(params[:id])
# => not defined
In any case, given the way ActiveModel is taking and according to best practices, it's better for you define all the public API of your model.
class Event
def self.find_by_slug!(slug)
where(slug: slug).first || raise(Mongoid::Errors::DocumentNotFound, self, slug: slug)
end
end
You can also re-use find_by_slug, but as I said, because ActiveRecord is deprecating find_by_attribute, I prefer to write the code directly.
I have an observer which looks like this:
class CommentObserver < ActiveRecord::Observer
include ActionView::Helpers::UrlHelper
def after_create(comment)
message = "#{link_to comment.user.full_name, user_path(comment.user)} commented on #{link_to 'your photo',photo_path(comment.photo)} of #{comment.photo.location(:min)}"
Notification.create(:user=>comment.photo.user,:message=>message)
end
end
Basically all I'm using it to do is create a simple notification message for a certain user when someone posts a comment on one of their photos.
This fails with an error message:
NoMethodError (undefined method `link_to' for #<CommentObserver:0x00000102fe9810>):
I would have expected including ActionView::Helpers::UrlHelper would solve that, but it seems to have no effect.
So, how can I include the URL helper in my observer, or else render this some other way? I would happily move the "message view" into a partial or something, but an observer has no associated views to move this to...
Why aren't you building the message when it's rendered out to the page and then caching it using something like this?
<% cache do %>
<%= render user.notifications %>
<% end %>
This would save you having to do a hack in the observer and would be more "standards compliant" in Rails.
To handle this type of thing, I made an AbstractController to generate the body of the email, then I pass that in as a variable to the mailer class:
class AbstractEmailController < AbstractController::Base
include AbstractController::Rendering
include AbstractController::Layouts
include AbstractController::Helpers
include AbstractController::Translation
include AbstractController::AssetPaths
include Rails.application.routes.url_helpers
include ActionView::Helpers::AssetTagHelper
# Uncomment if you want to use helpers
# defined in ApplicationHelper in your views
# helper ApplicationHelper
# Make sure your controller can find views
self.view_paths = "app/views"
self.assets_dir = '/app/public'
# You can define custom helper methods to be used in views here
# helper_method :current_admin
# def current_admin; nil; end
# for the requester to know that the acceptance email was sent
def generate_comment_notification(comment, host = ENV['RAILS_SERVER'])
render :partial => "photos/comment_notification", :locals => { :comment => comment, :host => host }
end
end
In my observer:
def after_create(comment)
email_body = AbstractEmailController.new.generate_comment_notification(comment)
MyMailer.new(comment.id, email_body)
end
So, it turns out this cannot be done for the same reason you can't use link_to in a mailer view. The observer has no information about the current request, and therefore cannot use the link helpers. You have to do it a different way.