I am using virtus(1.0.5) with rails (5.0.2). I am using Virtus for a model since it has validations based on the page being accessed.
My Organization model is as
class Organization < ApplicationRecord
validates :name, presence: true
end
and form created using virtus is as
class OrganizationProfileForm
include ActiveModel::Model
include Virtus.model
attribute :call_center_number, String, default: :org_call_center_number
validates :call_center_number, presence: true
def initialize(organization)
#organization = organization
end
private
def org_call_center_number
#organization.call_center_number
end
end
Unfortunately, the above code doesn't work
Loading development environment (Rails 5.0.2)
2.3.0 :001 > of = OrganizationProfileForm.new(Organization.last)
Organization Load (0.6ms) SELECT "organizations".* FROM "organizations" ORDER BY "organizations"."id" DESC LIMIT $1 [["LIMIT", 1]]
=> #<OrganizationProfileForm:0x007f9d61edd6a8 #organization=# <Organization id: 1, name: "Some name", call_center_number: "4892374928", created_at: "2017-03-29 09:35:22", updated_at: "2017-03-29 09:37:59">>
2.3.0 :002 > of.call_center_number
=> nil
We need to call super() in the initialize method.
Try removing the line private, as this may be preventing the call to the method org_call_center_number. The example given for default values on the Virtus repo uses a public instance method, not a private one.
See: What are the differences between "private", "public", and "protected methods"?
Related
I'm trying to abstract generic functions to a model concern on a Rails 5 with Mongoid app. This is the first app I do with mongoid and with other projects I had no problems implementing the next:
movie.rb
class Movie
include Mongoid::Document
include Genericable
field :name, type: String
field :year, type: Date
field :length, type: Integer
field :writers, type: Array
validates_presence_of :name, :year, :length
validates_uniqueness_of :name
index({name: 1}, {unique: true})
has_many :writers, class_name: "Person"
embeds_many :roles, class_name: "MovieRole"
end
genericable.rb (concern)
module Genericable
extend ActiveSupport::Concern
def self.s
all.map{|x| x}
end
end
(Methods are for demonstration purposes only).
When I try, on my rails console Movie.s I get next error:
NoMethodError: undefined method `s' for Movie:Class
Any clue about what I'm doing wrong? Thanks in advance for any help.
Setup
class Profile < ApplicationRecord
acts_as_paranoid
has_many :degreeholderships
has_many :degrees, through: :degreeholderships, dependent: :destroy
end
class Degreeholdership < ApplicationRecord
acts_as_paranoid column: :active, sentinel_value: true
belongs_to :profile
belongs_to :degree
validates :profile_id, presence: true
validates :degree_id, presence: true
def paranoia_restore_attributes
{
deleted_at: nil,
active: true
}
end
def paranoia_destroy_attributes
{
deleted_at: current_time_from_proper_timezone,
active: nil
}
end
end
class Degree < ApplicationRecord
has_many :degreeholderships
has_many :profiles, through: :degreeholderships, dependent: :destroy
end
Steps to reproduce:
call destroy method on profile.
entries in degreeholderships table are marked active=NULL and have deleted_at=timestamp
call restore method on profile and pass recursive: true
profile.restore(recursive: true)
entries in degreeholderships table stay the same
Expected outcome:
entries in degreeholderships that were associated with profile should be restored as well.
I have attempted to run restore with and without the recursive: true option as well as set the recovery_window value. All display this behavior. I have also removed the option to use the active column and revert back to using deleted_at (the default).
I'm looking to understand whether this behavior is:
Due to an error in my setup.
Actually the expected behavior and if so please explain why this is preferred over being able to restore the dependents recursively.
Is a bug with the gem.
Parameters: {"type"=>"restore", "id"=>"18"}
Pt Load (0.6ms) SELECT "pts".* FROM "pts" WHERE "pts"."deleted_at" IS NULL AND "pts"."id" = $1 LIMIT $2 [["id", 18], ["LIMIT", 1]]
overriding default queries works for all methods except destroy, really destroy, and restore
Completed 401 Unauthorized in 9ms (ActiveRecord: 1.3ms)
ActiveRecord::RecordNotFound (Couldn't find Product with 'id'=18 [WHERE "pts"."deleted_at" IS NULL]):
This is a simple 1 table with no associations ?
we're trying to get our site to have less scrapeable AND more readable urls
so e.g.
www.loomio.org/discussions/3122
becomes
www.loomio.org/d/3saA4ds9/lets-go-to-the-moon
we only really want the human-readable slug on show-links, so www.loomio.org/d/3saA4ds9/edit should be the url for editing that discussion
the solution so far follows the top answer here:
Ruby on Rails: How to override the 'show' route of a resource?
modify routes.rb:
get '/d/:id/:slug', to: 'discussions#show', as: :discussion
resources :discussions, path: 'd', except: [:edit, :show] do
get :activity_counts, on: :collection
member do
post :update_description
post :add_comment
post :show_description_history
get :new_proposal
post :edit_title
put :move
end
end
install gem FriendlyID; make and populated a :key column on Discussion table; add the following to discussion.rb (model):
KEY_LENGTH = 10
extend FriendlyId
friendly_id :key
write a custom path helper for group_path. in groups_helper.rb:
def group_url(group, options={})
url_for(options.merge(:controller => 'groups', :action => 'show',
:id => group.key, :slug => group.full_name.parameterize))
end
def group_path(group, options={})
group_url(group, options.merge(:only_path => true))
end
rake routes produces:
group GET /g/:id/:slug(.:format) groups#show
and while calling group_path(group) seems to work in some cases, I'm also seeing strange unrelated urls get generated, like :
http://loomio.org/group_requests/TegFOIx4DB/start_new_group?action=show&controller=groups%2Fgroups&slug=19-tory
in console, I'm also getting errors such as:
[5] pry(main)> g = Group.last
[6] pry(main)> app.group_path(g)
ActionController::RoutingError: No route matches {:controller=>"groups", :action=>"show", :id=>#<Group id: 2811, name: "Sylvester Buckridge", created_at: "2013-12-10 06:25:42", updated_at: "2013-12-10 06:25:42", privacy: "public", members_invitable_by: "members", parent_id: nil, email_new_motion: true, hide_members: false, beta_features: false, description: "A description for this group", memberships_count: 1, archived_at: nil, max_size: 300, cannot_contribute: false, distribution_metric: nil, sectors: nil, other_sector: nil, discussions_count: 0, motions_count: 0, country_name: nil, setup_completed_at: "2013-12-10 05:25:01", next_steps_completed: false, full_name: "Sylvester Buckridge", payment_plan: "undetermined", viewable_by_parent_members: false, key: "rkdlTytOin">}
from /home/s01us/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.16/lib/action_dispatch/routing/route_set.rb:540:in `raise_routing_error'
I've tried putting the group_path and grop_url methods in ApplicationController and ApplicationHelper to no avail.
calling
group_path( group.key, group.fullname.parameterize )
works, but would ideally like to be able to only have to call e.g.
group_path(#group)
as far as i understand the problem, you could use the good old hack with defining the to_param method on your model
class Group < ActiveRecord::Base
def to_param
"#{id}-#{slug}"
end
end
The beauty of this solution is that you won't need to do anything else. Rails will automatically use the to_param method as your record ID when it generates an URL from a record. You can do anything
redirect_to group_path(#group)
redirect_to #grup
# etc
and your Group.find should eat it as it is 123-smth-smth, usually it is smart enough to extract the integer part of the id
I am trying to validate the input of a state field using:
include ActionView::Helpers
class Credentials < ActiveRecord::Base
attr_accessible :license_number, ...:address_zip_code,
...
validates :license_number, presence: true, length: { minimum: 4 }
...
validates_inclusion_of :current_practice_address_state, :in => state_list
end
The variable state_list is an array described in helpers/credentials_helper.rb
Testing the model I run into undefined local variable error
$ bundle exec rspec spec/models/credentials_spec.rb
in `method_missing': undefined local variable or method `state_list' for #<Class:0x007f86a1844250> (NameError)
The helper class looks like:
module CredentialsHelper
state_list = %w(AL AK...WY)
end
Your call to include has to be inside the class:
class Credentials < ActiveRecord::Base
include ActionView::Helpers
...
end
am struggling with Ruby validates :confirmation => true in my Rails app. Consider the following code:
# == Schema Information
#
# Table name: things
#
# id :integer not null, primary key
# pin :integer(8)
# created_at :datetime
# updated_at :datetime
#
class Things < ActiveRecord::Base
#attr_accessor :pin
attr_accessible :pin, :pin_confirmation
validates :pin,
:confirmation => true,
:length => { :within => 7..15 },
:numericality => { :only_integer => true }
end
As the code is above, my validation works fine from the Rails console:
1.9.3-p0 :002 > l2 = Thing.create! :pin => 1234567, :pin_confirmation => 1111111
ActiveRecord::RecordInvalid: Validation failed: Pin doesn't match confirmation
....
1.9.3-p0 :003 > l2 = Thing.create! :pin => 1234567, :pin_confirmation => 1234567
=> #<Thing id: 2, pin: 1234567, created_at: "2012-01-30 22:03:29", updated_at: "2012-01-30 22:03:29">
but testing both through rspec and manually from rails server causes the validation to fail, saying they don't match when they darn well do. If I uncomment the attr_accessor for :pin, the validations will pass but the :pin of course will not be written to the database.
I'm completely sure I'm missing something obvious and vital- just running into a brick wall.
Like Frederick said above, the issue is comparing an instance of String with an instance of Integer.
More than likely, here's what you have in your controller:
Thing.new(params[:thing]) # note all these params come in as a string
What's happening is that since #pin is an integer column, you will get the following behaviour:
my_thing = Thing.new
my_thing.pin = "123456"
my_thing.pin # Will be the integer 123456, the attribute has been auto-cast for you
But since #pin_confirmed is just a regular attribute, not an integer column, here's the weirdness you will see:
my_thing = Thing.new
my_thing.pin_confirmation = "123456"
my_thing.pin_confirmation # Will be the *string* "123456", the attribute has been set as is
So naturally, in that case, no matter what values you have, since they come in through the "params" hash (which is always a set of strings), you will end up assigning string values to both attributes, but they will be cast to different types.
There are several ways to fix this.
One, you could create #pin_confirmation as an integer column in the database.
The other is you could add an attribute setter for #pin_confirmation of the following form:
def pin_confirmation=(val)
#pin_confirmation = val.to_i
end