Rails : Wrong number of arguments (given 1, expected 0) - ruby-on-rails

I get this error on my posts index page :
This the model :
class Post < ApplicationRecord
include Filterable
belongs_to :region
belongs_to :category
belongs_to :topic
validates :title, presence: true, length: { maximum: 500 }
validates :content, presence: true
validates :published_at, presence: true
translates :title, :content, :slug, touch: true, fallbacks_for_empty_translations: true
has_attached_file :image, styles: { thumb: "100x70#", featured: "1560x868#", small: "760x868#", big: ">1600x1600" }
validates_attachment :image, content_type: { content_type: ["image/jpeg", "image/gif", "image/png"] }
validates_attachment_presence :image
scope :published, -> (published) { where(published: (['true', true].include? published)).order(featured: :desc, published_at: :desc) }
scope :published_until_now, -> { where("published_at < ?", Time.now).merge(Post.published(true)) }
scope :topic, -> (topic_id) {
joins(:topic).where('topic_id = ?', topic_id) }
scope :category, -> (post_category) {
joins(:category).where('category_id = ?', post_category) }
scope :match, -> (search_term) {
with_translations(I18n.locale).where('content like ? or title like ?', "%#{search_term}%", "%#{search_term}%") }
self.per_page = 10
after_save :unfeature_older_posts, if: Proc.new { |post| post.featured? }
extend FriendlyId
friendly_id :title, use: :globalize
def unfeature_older_posts
featured_posts = Post.where(featured: true).where.not(id: id).order(published_at: :desc)
if featured_posts.size == 1
featured_posts.last.update(featured: false)
end
end
end
This the controller :
class PostsController < ApplicationController
before_action :get_pages_tree, :get_privacy_policy, only: [:index, :show]
def index
#filters = params.slice(:topic, :category)
#posts = Post.published_until_now
.filter(#filters)
.paginate(:page => params[:page], per_page: 11)
end
def show
#post = Post.friendly.find(params[:id])
end
end
and filter is defined here :
module Filterable
extend ActiveSupport::Concern
module ClassMethods
def filter(filtering_params)
results = self.where(nil)
filtering_params.each do |key, value|
results = results.public_send(key, value) if value.present?
end
results
end
end
end
I'm not sure where to go from here. I recently upgraded to Ruby on Rails 5 and Ruby 2.7.0, I don't know if it's related.

Try replacing module ClassMethods with class_methods do.
If it works, then please keep in mind:
filter method comes from Ruby. It's defined in Array. As you can see in the doc, filter method on Array takes no argument. That's the direct cause of the error you see.
In Rails, when methods on Array are called on ActiveRecord object (in your case, Post.published_until_now) and when methods cannot be found on a model, it automatically converts itself into an Array. So, it calls filter method on Array. Generally, you don't want to define methods such as filter which is confusing.

Related

Rails Order by Scope with Draper/Decorate from other model

So I have a pretty complex model that is using a scope to establish what is considered online and what is considered offline. Then in my admin module I'm displaying all of the available devices. What I'm looking to do is then order by those that are currently online.
So the model looks like:
class Device < ActiveRecord::Base
include Tokenizer
belongs_to :user
belongs_to :organization
belongs_to :former_user, class_name: 'User', foreign_key: 'former_user_id'
belongs_to :order
belongs_to :replaced_by_device, class_name: 'Device', foreign_key: 'replaced_by_device_id'
has_and_belongs_to_many :user_clients, join_table: :user_clients_devices
has_many :user_client_speed_tests, through: :user_clients
validates :hardware_token, uniqueness: true, presence: true, length: { maximum: 50 }
validates :mac, mac_address: true, allow_blank: false, allow_nil: true
before_validation :generate_hardware_token, on: :create
before_validation :assign_organization_id_if_missing
validate :existence_of_user_id, if: :user_id?
validate :existence_of_organization_id, if: :organization_id?
validates_numericality_of :user_id, :organization_id, allow_nil: true, greater_than_or_equal_to: 0
alias_attribute :name, :mac
scope :with_macs, -> { where("mac IS NOT NULL AND hardware_mac <> ''") }
scope :without_macs, -> { where("mac IS NULL OR hardware_mac = ''") }
scope :with_old_macs, -> { where("mac LIKE :prefix", prefix: "C0%") }
scope :with_new_macs, -> { where("mac LIKE :prefix", prefix: "A%") }
scope :without_user, -> { where(user_id: nil) }
scope :with_user, -> { where.not(user_id: nil) }
scope :online, -> { where("last_seen_at > ?", 1.hour.ago) }
scope :offline, -> { where.not(id: online.ids) }
scope :installed_online, -> { installed.online }
scope :installed_offline, -> { installed.where.not(id: installed_online.ids) }
enum status: [ :operational, :replaced ]
after_save :set_provisioned_if_needed
has_paper_trail
ransacker :mac_address_presence, formatter: proc{ |value|
value.eql?('present') ? with_macs.ids : without_macs.ids
}, splat_params: true do |parent| parent.table[:id] end
ransacker :mac_address_type, formatter: proc{ |value|
value.eql?('old') ? with_old_macs.ids : with_new_macs.ids
}, splat_params: true do |parent| parent.table[:id] end
ransacker :organization_presence, formatter: proc{ |value|
value.eql?('present') ? with_organization.ids : without_organization.ids
}, splat_params: true do |parent| parent.table[:id] end
ransacker :installation_status, formatter: proc{ |value|
case value
when 'installed' then installed.ids
when 'not_installed' then not_installed.ids
when 'not_assigned' then not_assigned.ids
end
}, splat_params: true do |parent| parent.table[:id] end
ransacker :connection_status, formatter: proc{ |value|
data = value.eql?('online') ? online.ids : offline.ids
data.any? ? data : nil
}, splat_params: true do |parent| parent.table[:id] end
ransacker :wifi_signal_strength, formatter: proc{ |value|
data = case value
when 'borderline' then with_borderline_signal_strength.ids
when 'bad' then with_bad_signal_strength.ids
when 'ok' then with_ok_signal_strength.ids
when 'good' then with_good_signal_strength.ids
else with_great_signal_strength.ids end
data.any? ? data : nil
}, splat_params: true do |parent| parent.table[:id] end
def update_status(new_status)
update!(status: new_status, status_last_changed_at: Time.now.utc)
end
def can_replace_hw?
operational? && (order.nil? || (order.present? && order.completed?))
end
def last_user_client
user_clients.last
end
def last_user_client_speed_test
last_user_client.last_speed_test if last_user_client.present?
end
def speed_tests
user_client_speed_tests
end
def has_last_user_client?
last_user_client.present?
end
def has_been_seen?
has_last_user_client? && last_user_client.last_seen_at.present?
end
def offline?
if has_been_seen?
last_user_client.last_seen_at < 1.hour.ago
end
end
def online?
if has_been_seen?
last_user_client.last_seen_at > 1.hour.ago
end
end
def connection_status_history
last_seen_history = last_seen_histories.where('last_seen_at > ?', 2.weeks.ago).order(:last_seen_at).to_a
status_history = []
while last_seen_history.present?
next_last_seen = last_seen_history.shift
status_history << {
status: "Online",
timestamp: next_last_seen.last_seen_at.in_time_zone(Time.now.zone)
}
if (last_seen_history.first&.last_seen_at || Time.current) - status_history.last[:timestamp] > 1.hour
status_history << {
status: "Offline",
timestamp: status_history.last[:timestamp].in_time_zone(Time.now.zone) + 1.hour
}
end
end
status_history
end
end
Then in my admin view I have an input I'm referencing with:
= f.input :user_device_ids, label: false, as: :select, multiple: true, collection: #organization.available_devices.decorate
So from the organization I'm wanting to order by the online Devices. I thought I could do something like #organization.available_devices.order(online).decorate. That clearly fails because online is a scope of Devices not from Organization. So if I do something like #organization.available_devices.order(Device.online).decorate I get no errors. That seems wrong/sloppy.
How do I accurately display for the collection the online devices in the different model?
Two things came up looking at your code sample:
You have belongs_to :order which could easily be confused with ActiveRecord's order method: https://apidock.com/rails/ActiveRecord/QueryMethods/order
If you temporarily remove that belongs_to :order and try #organization.available_devices.order(:last_seen_at, :desc).decorate
things should work as expected.
Hope that this helps.

Rails Create new active record with association value passed in params

I have 2 rails models which look like this
class Physician < UserProfile
has_many :state_licenses, inverse_of: :physician, autosave: true, dependent: :destroy
validates :state_licenses, :length => { :minimum => 1, message: "Please select at-least one state license"}
class StateLicense < ApplicationRecord
include RailsAdminPhysicianDependencyConcern
belongs_to :physician, inverse_of: :state_licenses
belongs_to :state, optional: true
attr_accessor :client_id
validates :state, presence: { message: I18n.t("errors.choose_one", field: 'state') }
#validates :license_number, presence: { message: I18n.t("errors.blank") }
def name
return "" unless state
"#{state.try(:name)}"
end
end
In my controller, I am using the code below to create a new Physician record with a bunch of state licenses but for some reason, the state licenses I pass to the create function never make it to the Physician model
def create
physician = nil
ActiveRecord::Base.transaction do
state_licenses = params["state_licenses"]
state_licenses_For_Association = []
if (state_licenses != nil)
state_licenses.each do |state_license|
sl = {}
sl[:state_id] = state_license
state_licenses_For_Association.push(sl)
end
end
physician = Physician.create(params.permit(:first_name, :last_name, :title, :residency_board_status, :residency_specialty_id, :state_licenses => state_licenses_For_Association))
user_record = nil
super do |user|
user_record = user
user.errors.delete(:user_profile)
physician.errors.messages.each { |field, messages| messages.each {|message| user.errors.add(field, message)} }
end
raise ActiveRecord::Rollback unless user_record.persisted? && physician.persisted?
end
AdminNotificationsMailer.physician_signed_up(physician).deliver_now rescue nil
end
What am I doing wrong?
Try changing this:
physician = Physician.create(params.permit(:first_name, :last_name, :title, :residency_board_status, :residency_specialty_id, :state_licenses => state_licenses_For_Association))
to this:
physician = Physician.create(params.permit(:first_name, :last_name, :title, :residency_board_status, :residency_specialty_id).merge(state_licenses: state_licenses_For_Association)) # note the .merge call

Advance search with elasticsearch and rails

I want to use ElasticSearch to search with multiple parameters (name, sex, age at a time).
what I've done so far is included elastic search in my model and added a as_indexed_json method for indexing and included relationship.
require 'elasticsearch/model'
class User < ActiveRecord::Base
include Elasticsearch::Model
include Elasticsearch::Model::Callbacks
belongs_to :product
belongs_to :item
validates :product_id, :item_id, :weight, presence: true
validates :product_id, uniqueness: {scope: [:item_id] }
def as_indexed_json(options = {})
self.as_json({
only: [:id],
include: {
product: { only: [:name, :price] },
item: { only: :name },
}
})
end
def self.search(query)
# i'm sure this method is wrong I just don't know how to call them from their respective id's
__elasticsearch__.search(
query: {
filtered: {
filter: {
bool: {
must: [
{
match: {
"product.name" => query
}
}
],
must: [
{
match: {
"item.name" => query
}
}
]
}
}
}
}
)
end
end
User.import force: true
And In controller
def index
#category = Category.find(params[:category_id])
if params[:search].present? and params[:product_name].present?
#users = User.search(params[:product_name]).records
end
if params[:search].present? and params[:product_price].present?
#users = User.search(params[:product_price]).records
end
if params[:search].present? and params[:item].present?
if #users.present?
#users.search(item: params[:item], product: params[:product_name]).records
else
#users = User.search(params[:item]).records
end
end
end
There are basically 3 inputs for searching with product name , product price and item name, This is what i'm trying to do like if in search field only product name is present then
#users = User.search(params[:product_name]).records
this will give me records but If user inputs another filter say product price or item name in another search bar then it's not working. any ideas or where I'm doing wrong :/ stucked from last 3 days

friendly_id slug not changing on update

I'm using friendly_id 5.0.0.rc1, and also active_admin.
It would appear everything is working perfectly as expected, except for the fact that updating a record's slug attribute/column in active_admin does not do anything (it keeps it the same)
I find the same behavior just using console:
p = Post.first
p.slug
#=> 'test'
p.slug = 'another-test'
p.save
#=> true
p.slug
#=> 'test
My config:
FriendlyId.defaults do |config|
config.use :reserved
config.reserved_words = %w(admin new edit index session users register)
config.use :finders
config.use :slugged
config.slug_column = 'slug'
config.sequence_separator = '-'
config.use Module.new {
def should_generate_new_friendly_id?
slug.blank? || slug_changed?
end
}
end
My model:
class Post < ActiveRecord::Base
default_scope { order('created_at DESC') }
validates :title, presence: true
validates :body, presence: true
validates :views, presence: true, numericality: { only_integer: true }
extend FriendlyId
friendly_id :title, use: [:slugged, :history]
end
my controller:
class PostsController < ApplicationController
def index
#posts = Post.all.page(params[:page]).per(10)
end
def show
#post = Post.find_by_slug!(params[:id])
if request.path != post_path(#post)
redirect_to #post, :status => :moved_permanently and return
else
#post.increment :views if #post
end
end
end
Thanks!
Usually when using friendly id, you never update the slug manually. Instead:
def should_generate_new_friendly_id?
slug.blank? || title_changed?
end
And then every time you change the title, it will automatically update the slug.
more exactly, you should use self.title_changed?
def should_generate_new_friendly_id?
slug.blank? || self.title_changed?
end
Incase anyone else lands here and just need to change a slug:
p = Post.first
p.slug
#=> 'test'
tmp_title = p.title
p.title = 'another-test'
p.slug = nil
p.save
#=> true
p.title = tmp_title
p.slug
#=> 'another-test'

Is possible to use Rails ActiveModel::Validations per instance?

theres an excerpt of my code:
module Configuracao
extend self
class Key
include ActiveModel::Validations
attr_accessor :name, :type, :default, :validations, :group, :available_values
def initialize(params)
params.symbolize_keys!.assert_valid_keys(:name, :type, :default, :validations, :group, :available_values)
#group = params[:group]
#name = params[:name]
#type = params[:type]
#available_values = params[:available_values]
#default = params[:default]
#validations = params[:validations]
#in this way each validation is being added for all keys
Configuracao::Key.class_eval do
validates :value, params[:validations]
end
end
end
end
so for every instance key i will have a diferent validation passed in a hash, example:
Key.new( validations: { presence: true, numericality: true } )
Key.new( validations: { length: { maximum: 30 } } )
There's a way to do it?
well i found a solution, maybe not so elegant or best way to do, but it works
def initialize(params)
params.symbolize_keys!.assert_valid_keys(:name, :type, :default, :validations, :group, :available_values)
#group = params[:group]
#name = params[:name]
#type = params[:type]
#available_values = params[:available_values]
#default = params[:default]
##current_validations = nil
##current_validations = #validations = params[:validations]
class << self
validates :value, ##current_validations unless ##current_validations.blank?
end
end
now each time i instantiate a Key, the class will be modified only for that instance
Will this work?
...
validates :all_hash_validations_pass
...
def all_hash_validations_pass
...iterate through the hash here, and validate each of them
end
If not, you should be able to use a custom validator for more control.

Resources