I want to include the routes and the link_to method in a PORO. While testing this in the console I came accross this:
If I include UrlHelper without the routes helper everything seems to work fine:
ruby-1.9.3-rc1 :001 > Rails.version
=> "3.2.0.rc2"
ruby-1.9.3-rc1 :001 > include ActionView::Helpers::UrlHelper
=> Object
ruby-1.9.3-rc1 :002 > link_to "foo", Rails.application.routes.url_helpers.ponies_path
=> "foo"
If I include the routes:
ruby-1.9.3-rc1 :001 > include ActionView::Helpers::UrlHelper
ruby-1.9.3-rc1 :003 > include Rails.application.routes.url_helpers
=> Object
ruby-1.9.3-rc1 :004 > link_to "foo", ponies_path
I get the following error:
NameError: undefined local variable or method `controller' for #<ApplicationController:0x007fa1497ecc40>
What am I doing wrong here?
As suggested you should use the app object for the routes part and you should be using the helper object for the link_to.
No need to include any of the helpers through Ruby when using the console:
helper.link_to "foo", app.ponies_path
Use the app object.
> link_to "foo", app.ponies_path
Related
In my application_controller.rb, i have a line of code as follows:
def index
CaseStatus.order(:application_source).pluck(:application_source).uniq!
end
In my rspec code, i have a line of code that visits the index path of application_controller as follows
visit applications_path
When i run the code directly, it works perfectly but when it visits application_controller.rb via rspec, i get an error which says
NoMethodError:
undefined method `compact' for nil:NilClass
Not sure while i get this error via rspec and capybara but if i run the code as
def index
CaseStatus.order(:application_source).pluck(:application_source)
end
It executes perfectly with no errors. Kinda confused what the uniq! breaks in the code that suddenly the result becomes nil.
i get this error
Failure/Error: #application_channels = CaseStatus.order(:application_source).pluck(:application_source).uniq!.compact if CaseStatus.order(:application_source).present?
NoMethodError:
undefined method `compact' for nil:NilClass
# ./app/controllers/loan_applications_controller.rb:53:in `index'
I do not think uniq! is the method you would like to use in this case, see:
Returns nil if no changes are made (that is, no duplicates are found).
https://ruby-doc.org/core-2.2.0/Array.html#method-i-uniq-21
So it works like this:
2.3.1 :008 > a = [1,2,3,3,nil].uniq!
=> [1, 2, 3, nil]
2.3.1 :009 > a = [1,2,3,nil].uniq!
=> nil
2.3.1 :010 >
on the other hand uniq works like:
2.3.1 :010 > a = [1,2,3,3,nil].uniq
=> [1, 2, 3, nil]
2.3.1 :011 > a = [1,2,3,nil].uniq
=> [1, 2, 3, nil]
and on the output of uniq it is safe to run compact to remove nil values.
What is the difference between Ruby’s Hash and ActiveSupport’s HashWithIndifferentAccess? Which is the best for dynamic hashes?
Below is the simple example that will show you difference between simple ruby hash & a "ActiveSupport::HashWithIndifferentAccess"
HashWithIndifferentAccess allows us to access hash key as a symbol or string
Simple Ruby Hash
$ irb
2.2.1 :001 > hash = {a: 1, b:2}
=> {:a=>1, :b=>2}
2.2.1 :002 > hash[:a]
=> 1
2.2.1 :003 > hash["a"]
=> nil
ActiveSupport::HashWithIndifferentAccess
2.2.1 :006 > hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1, b:2)
NameError: uninitialized constant ActiveSupport
from (irb):6
from /home/synerzip/.rvm/rubies/ruby-2.2.1/bin/irb:11:in `<main>'
2.2.1 :007 > require 'active_support/core_ext/hash/indifferent_access'
=> true
2.2.1 :008 > hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1, b:2)
=> {"a"=>1, "b"=>2}
2.2.1 :009 > hash[:a]
=> 1
2.2.1 :010 > hash["a"]
=> 1
class HashWithIndifferentAccess is inherited from ruby "Hash" & above special behavior is added in it.
In Ruby Hash:
hash[:key]
hash["key"]
are different. In HashWithIndifferentAccess as the name suggests, you can access key either way.
Quoting official documentation to this:
Implements a hash where keys :foo and "foo" are considered to be the
same.
and
Internally symbols are mapped to strings when used as keys in the
entire writing interface (calling []=, merge, etc). This mapping
belongs to the public interface. For example, given:
hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1)
You are
guaranteed that the key is returned as a string:
hash.keys # => ["a"]
With some trepidation, I decided to subclass ActiveSupport::TimeZone, but I can't get very far because when I call [] on my subclass it fails to invoke the superclass's [] method. I thought it might have had something to with the fact that the operator overload happens in a class method, so I tried this:
Loading development environment (Rails 4.2.1)
2.2.1 :001 > class Foo; def Foo.[](f); f; end; end
=> :[]
2.2.1 :002 > Foo['baz']
=> "baz"
2.2.1 :003 > class Bar < Foo; end
=> nil
2.2.1 :004 > Bar['baz']
=> "baz"
So that worked exactly as I thought it would. But if that works, why does this fail?
2.2.1 :005 > ActiveSupport::TimeZone["America/New_York"]
=> #<ActiveSupport::TimeZone:0x007f80835c18a8 #name="America/New_York", #utc_offset=nil, #tzinfo=#<TZInfo::TimezoneProxy: America/New_York>, #current_period=#<TZInfo::TimezonePeriod: #<TZInfo::TimezoneTransitionDefinition: #<TZInfo::TimeOrDateTime: 1425798000>,#<TZInfo::TimezoneOffset: -18000,3600,EDT>>,#<TZInfo::TimezoneTransitionDefinition: #<TZInfo::TimeOrDateTime: 1446357600>,#<TZInfo::TimezoneOffset: -18000,0,EST>>>>
2.2.1 :006 > class T < ActiveSupport::TimeZone; end
=> nil
2.2.1 :007 > T["America/New_York"]
NoMethodError: undefined method `[]' for nil:NilClass
The method relies on calling [] on an #lazy_zones_map instance variable, which your subclass does not have.
Edit: an example of the behavior:
class Foo
#foo = []
def self.[](arg)
#foo[arg]
end
end
class Bar < Foo
end
Foo[0] #=> nil
Bar[0] #=> undefined method `[]` for nil:NilClass
In app/services, I have some classes, as Notification::Finder and Notification::Builder.
They are placed as app/services/notification/builder.rb and app/services/notification/finder.rb.
There is also the Notification class as a model, at app/models/notification.rb
The autoload_path is configurated as in config.autoload_paths += %W(#{config.root}/app/services)
When I try to load Finder, it works:
Loading development environment (Rails 3.2.9)
[1] pry(main)> Notification::Finder
=> Notification::Finder
But when I try the Builder, I get a problem with the rails autoloading:
Loading development environment (Rails 3.2.9)
[1] pry(main)> Notification::Builder
=> ActiveRecord::Associations::Builder
It just ignores the namespace I've used when the constant name (Builder) has already been defined by other namespace, and gets the ActiveRecord::Associations::Builder instead.
Is this the expected behavior, or a rails bug?
Going more detailed, the const_missing method at activesupport/dependencies.rb receives a const_name 'Builder', and nesting.inspect => 'nil'.
Curious that when I use constantize, it resolves as expected:
Loading development environment (Rails 3.2.9)
[1] pry(main)> 'Notification::Builder'.constantize
=> Notification::Builder
( Rails issue at github: https://github.com/rails/rails/issues/8726 )
ActiveRecord::Associations::Builder is a module in Rails. If you have a Notification::Builder, you can ask it its class:
>> Notification::Builder
=> ActiveRecord::Associations::Builder
>> Notification::Builder.class
=> Module
>> Notification::Builder.ancestors
=> [ActiveRecord::Associations::Builder]
Is this expected behavior?
Yes
OK, so... what choices do you have?
You can use a different term than Builder. Like Factory. or Notification::NotificationBuilder
More info:
* http://www.rubydoc.info/docs/rails/3.1.1/ActiveRecord/Associations/Builder/Association
* http://apidock.com/rails/ActiveRecord/Associations/Builder
This problem exists because you are using an ActiveRecord model as a namespace. I created a gist with some experimentation until I saw the root cause.
ActiveRecord models include the ActiveRecord::Associations module. Since you can get to a constant when including a module the Builder constant defined within Associations is now also reachable through the AR model. You will get this behavior with every class defined in the modules, which are included into an AR model:
1.9.3-p194 :010 > Post.ancestors
=> [Post(id: integer, title: string, published_at: datetime, created_at: datetime, updated_at: datetime), Post::GeneratedFeatureMethods, #<Module:0x007fec74dc33a0>, ActiveRecord::Base, ActiveRecord::Core, ActiveRecord::Store, ActiveRecord::Serialization, ActiveModel::Serializers::Xml, ActiveModel::Serializers::JSON, ActiveModel::Serialization, ActiveRecord::Reflection, ActiveRecord::Transactions, ActiveRecord::Aggregations, ActiveRecord::NestedAttributes, ActiveRecord::AutosaveAssociation, ActiveModel::SecurePassword, ActiveRecord::Associations, ActiveRecord::Timestamp, ActiveModel::Validations::Callbacks, ActiveRecord::Callbacks, ActiveRecord::AttributeMethods::Serialization, ActiveRecord::AttributeMethods::Dirty, ActiveModel::Dirty, ActiveRecord::AttributeMethods::TimeZoneConversion, ActiveRecord::AttributeMethods::PrimaryKey, ActiveRecord::AttributeMethods::Query, ActiveRecord::AttributeMethods::BeforeTypeCast, ActiveRecord::AttributeMethods::Write, ActiveRecord::AttributeMethods::Read, ActiveRecord::AttributeMethods, ActiveModel::AttributeMethods, ActiveRecord::Locking::Pessimistic, ActiveRecord::Locking::Optimistic, ActiveRecord::CounterCache, ActiveRecord::Validations, ActiveModel::Validations::HelperMethods, ActiveSupport::Callbacks, ActiveModel::Validations, ActiveRecord::Integration, ActiveModel::Conversion, ActiveRecord::AttributeAssignment, ActiveModel::ForbiddenAttributesProtection, ActiveModel::DeprecatedMassAssignmentSecurity, ActiveRecord::Sanitization, ActiveRecord::Scoping::Named, ActiveRecord::Scoping::Default, ActiveRecord::Scoping, ActiveRecord::Inheritance, ActiveRecord::ModelSchema, ActiveRecord::ReadonlyAttributes, ActiveRecord::Persistence, Object, PP::ObjectMixin, ActiveSupport::Dependencies::Loadable, V8::Conversion::Object, JSON::Ext::Generator::GeneratorMethods::Object, Kernel, BasicObject]
A possible solution is to use a module as a namespace. For example module Notifications.
I have a HTML/CSS File laid out with a bunch of areas that need adding. I have a ruby on rails application that would have a bunch of form elements that would then need to be added to this HTML/CSS file (it doesn't need to be shown or anything, just edited and then saved). I don't really understand how I can do this. I was looking at the file class, but got lost very quickly.
Any easy way to do this?
Writing to a file in Ruby is very simple:
File.open(filename, 'w') do |f|
f.write(content)
end
For an example in Rails try the following steps. Generate a new Rails app and a dummy scaffold by running:
rails new erbfun
cd erbfun
rails g scaffold Stylesheet custom_css:text
rake db:migrate
mkdir -p public/system/stylesheets
Then do something like this in your model:
class Stylesheet < ActiveRecord::Base
require 'erb'
FOLDER = File.join(Rails.public_path,'system/stylesheets')
TEMPLATE = <<-CSS
body {
font-family: Helvetica;
}
<%= custom_css %>
/* some css comment here ... */
CSS
def save_to_file
template = ERB.new(TEMPLATE)
document = template.result(binding)
filename = File.join(FOLDER,"stylesheet-#{Time.now.to_i}.css")
File.open(filename, 'w') do |f|
f.write(document)
end
end
end
and then try it out:
$ rails c
Loading development environment (Rails 3.2.2)
1.9.3p125 :001 > s = Stylesheet.new custom_css: 'foobar'
=> #<Stylesheet id: nil, custom_css: "foobar", created_at: nil, updated_at: nil>
1.9.3p125 :002 > s.save!
...
=> true
1.9.3p125 :003 > s.save_to_file
=> 94
1.9.3p125 :004 > exit
$ cat public/system/stylesheets/stylesheet-1332633386.css
body {
font-family: Helvetica;
}
foobar
/* some css comment here ... */