I recently updated my Rails app from 4.0 to 4.1. Everything seems to work fine, except this one line in my Resource_Tag Model that was working before.
Essentially, I want to search/find District_Resources by Tag Name and by the District_Resource Name.
**ex.**
If I search the word "Tutoring"
*I should get all District_Resources with the Resource_Tag "Tutoring"
*And all District Resources that include the word Tutoring in it's Name.
(i.e Tutoring Services)
For some reason, I keep getting this error:
wrong number of arguments (1 for 0)
all(:conditions => (string ? [cond_text, *cond_values] : []))
CONTROLLER
class ResourceTagsController < ApplicationController
def index
if params[:search].present?
#Calls Search Model Method
#resource_tags = ResourceTag.search(params[:search])
#tagsearch = ResourceTag.search(params[:search])
#tag_counts = ResourceTag.count(:group => :name,
:order => 'count_all DESC', :limit => 100)
else
#resource_tags = ResourceTag.all
end
end
end
MODELS
class DistrictResource < ActiveRecord::Base
has_many :district_mappings, dependent: :destroy
has_many :resource_tags, through: :district_mappings
accepts_nested_attributes_for :resource_tags
end
class ResourceTag < ActiveRecord::Base
#create relationships with all resource and mapping models
has_many :district_mappings, dependent: :destroy
has_many :district_resources, through: :district_mappings
#I GET AN ERROR HERE
def self.search(string)
return [] if string.blank?
cond_text = string.split(', ').map{|w| "name like ?"}.join(" OR ")
cond_values = string.split(', ').map{|w| "%#{w}%"}
all(:conditions => (string ? [cond_text, *cond_values] : []))
end
end
VIEWS
<%= form_tag(resource_tags_path, :method => 'get', class: "navbar-search") do %>
<form>
<%= text_field_tag :search, params[:search], :class => "search-query form-control" %>
<%= submit_tag "Search", :name => nil, :class => "search-button" %>
</form>
<% end %>
After an hour search I came to know that In rails 4.1 onward all method of ActiveRecord does not take any parameters that's why extra argument error occurs. You can try where instead. Here is your search method
def search(string)
return [] if string.blank?
cond_text = string.split(', ').map{|w| "name like ?"}.join(" OR ")
cond_values = string.split(', ').map{|w| "%#{w}%"}
self.where(string ? [cond_text, *cond_values] : [])
end
Related
I'm following this tutorial on how to nest other Models in my Devise registration form. I'm getting an error in my New controller:
'NoMethodError in Users::RegistrationsController#new undefined method `languages_user=' for #'.
Languages_Users is a join table, and I'm wondering if this is the reason it isn't working, but I don't understand what the solution is. I want to add 2 different records of Languages_Users when the user signs up.
Models:
User.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
belongs_to :role
has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100#" }, :default_url => "/images/:style/missing.png"
validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
validates_presence_of :first_name, :last_name, :location, :nationality, :bio
before_save :assign_role
def assign_role
self.role = Role.find_by name: "user" if self.role.nil?
end
has_many :languages_users
has_many :languages, :through => :languages_users
accepts_nested_attributes_for :languages_users
Language.rb
class Language < ActiveRecord::Base
has_many :languages_users
has_many :users, :through => :languages_users
end
Langauges_user.rb
class LanguagesUser < ActiveRecord::Base
belongs_to :user
belongs_to :language
validates_presence_of :user_id, :language_id, :level
validates :user_id, :uniqueness => {:scope => :language_id, :message => 'can only delcare each language once. Please change the level of the language in Manage Languages.'}
end
Controllers:
registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
def new
build_resource({})
self.resource.languages_user = LanguagesUser.new[sign_up_params]
respond_with self.resource
end
def create
#user_id = current_user.id
super
end
def sign_up_params
allow = [:email, :password, :password_confirmation, [languages_user_attributes: [:language_id, :user_id, :level]]]
end
end
Relevant sections of User's new.html.erb
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<%= f.fields_for :langauges_user do |lu| %>
<%#= lu.text_field :language_id %>
<%= lu.collection_select(:language_id, Language.order('language ASC').all, :id, :language) %><br>
<%= lu.hidden_field languages_user[level], value: 1 %>
<% end %>
<%= f.submit "Sign up" %>
<% end %>
Relevant routes
Rails.application.routes.draw do
resources :languages_users
devise_for :users, controllers: { registrations: "users/registrations" }
resources :users
get 'languages_users/:id/sign_up', to: 'languages_users#sign_up', as: 'sign_up'
end
I'm still learning - so please let me know if you need to see anything else. Thanks!
I'm not that up to speed on Devise as I only recently started using it myself, but if I understand correctly it's not a Devise related problem - just harder to get a fix on because of Devise's self.resource abstraction.
You've deviated from your tutorial in an important respect: in the tutorial a User creates a Company, but the Company has_many :users. In your case the User creates a LanguagesUser, but here, the User has_many :languages_users. This means new syntax. This line, that's causing your error currently:
self.resource.languages_user = LanguagesUser.new[sign_up_params]
Needs to be along the lines of:
self.resource.languages_users.build(sign_up_params) #but see below re sign_up_params
Or if you want to save the associated resource right off the bat (I assume not, since you're not at the moment), you can use create or create! instead of build.
Aside
You may run into different trouble with your sign_up_params method, which also appears to have deviated from the tutorial - it doesn't actually use the allow array to whitelist any params, at least as written in your question. In any case, note they didn't use it when instantiating the Company, so it may not be fit for purpose when building your LanguagesUser, either.
A simple call to sign_up_params[:languages_user_attributes] should get you over the line, once you've fixed the sign_up_params method. Or you can set the nested object up with its own params whitelist.
I am new to ROR and using active admin for generating a small app. I have belongs to and has many relation ships defined in the models. My app is working good for the pages where belongs to does not apply. In the page where belongs to comes into action I have drop down created by Active Admin, however when I select the values from drop down and save the form, values selected from drop down is not getting saved. below are my model controller and active admin pages codes. Please help me fix this issue.
ActiveAdmin.register Componentdetail do
models:
class Preference < ActiveRecord::Base
def permitted_params
params.permit preference: [:prefname, :prefdisplay, :helptext]
end
def preference_params
params.require(:preference).permit(:prefname, :prefdisplay, :helptext)
end
attr_accessible :prefname, :prefdisplay, :helptext
has_many :prefcomprelation
#accepts_nested_attributes_for :prefcomprelation, :allow_destroy => true
def display_name
return self.prefname
end
def input
self.id
end
end
class Prefcomprelation < ActiveRecord::Base
def permitted_params
params.permit prefcomprelation: [:comment, :preference, :componentdetail]
end
def prefcomprelation_params
params.require(:prefcomprelation).permit(:comment, :preference, :componentdetail)
end
# def to_s
# description
# end
attr_accessible :comment, :preference, :componentdetail
#acts_as_list column: :preference, :scope => :preference
belongs_to :preference
#acts_as_list column: :componentdetail, :scope => :componentdetail
belongs_to :componentdetail
validates :comment, presence: true
validates :preference, presence: true
validates :componentdetail, presence: true
#controller do
def new
#prefcomprelation = Prefcomprelation.new
end
def update
#prefcomprelation = Prefcomprelation.new(precomprelation_params)
#prefcomprelation.save
end
def create
#prefcomprelation = Prefcomprelation.new(precomprelation_params)
#prefcomprelation.save
end
#end
end
class Message < ActiveRecord::Base
def permitted_params
params.permit message: [:message, :componentdetail]
end
def message_params
params.require(:message).permit(:message, :componentdetail)
end
attr_accessible :message, :componentdetail
belongs_to :componentdetail
end
class Componentdetail < ActiveRecord::Base
def permitted_params
params.permit componentdetail: [:compname, :compdisplay, :prefcomprelation]
end
def componentdetail_params
params.require(:componentdetail).permit(:compname, :compdisplay, :prefcomprelation)
end
attr_accessible :compname, :compdisplay, :prefcomprelation
has_many :prefcomprelation
#accepts_nested_attributes_for :prefcomprelation, :allow_destroy => true
has_many :message
#accepts_nested_attributes_for :message, :allow_destroy => true
def name
return self.compname
end
end
controllers
class PreferenceController < ApplicationController
def index
#preference = Preference.all
end
def show
end
end
class PrefcomprelationController < ApplicationController
def index
#prefcomprelation = Prefcomprelation.all
end
def create
#prefcomprelation = Prefcomprelation.new(precomprelation_params)
#prefcomprelation.save
end
def new
#prefcomprelation = Prefcomprelation.new(precomprelation_params)
#prefcomprelation.save
end
def show
end
end
class MessageController < ApplicationController
def index
#message = Message.all
end
def create
#message = Message.new(message_params)
#message.save
end
def show
end
end
class ComponentdetailController < ApplicationController
def index
#componentdetail = Componentdetail.all
end
def show
end
end
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
end
Admin Pages
ActiveAdmin.register Preference do
end
ActiveAdmin.register Prefcomprelation do
index do
selectable_column
id_column
column :comment
column :preference
column :created_at
actions
end
filter :comment
filter :preference
filter :componentdetail
form do |f|
f.inputs "Prefcomprelation" do
f.input :comment
#f.inputs do
f.input :preference
f.input :componentdetail
end
f.actions
# f.input :preference
end
end
ActiveAdmin.register Message do
index do
column :message
column :created_at
actions
end
form :html => { :enctype => "multipart/form-data" } do |f|
f.inputs 'Details' do
f.input :message
f.input :componentdetail
end
f.actions
end
end
ActiveAdmin.register Componentdetail do
end
issue comes when I try to create new Prefcomprelation and select preference and componentdetails value from the dropdown menu and try to save.
same happens to the message page.
form do |f|
f.inputs "Product Details" do
f.input :name, :as => :select,
:collection => Product.all.map{|u| ["#{u.product_name}", u.product_name]}
f.input :description
f.input :image
f.input :quantity
end
f.actions
end
Try to add drop down like above and save select value in active admin.
Build some simple project and stack on using accepts nested attributes + form_for.
Now i have no problem with code, all work and save, but when i uncomment accepts_nested_attributes_fori have error or my model doesnt create (i try differente variant for last 5 days, but can t build this right..). I think i have problem in controller.. My code (which works without accepted_nested_attributes).
Model:
class Project < ActiveRecord::Base
belongs_to :user
has_one :j_project
has_one :p_project
# accepts_nested_attributes_for :p_project, :j_project
validates :user_id, :title, presence: true
end
View:
= form_for(#project) do |f|
= f.label :title
= f.text_field :title
= fields_for #p_project do |fa|
= fa.label :requester
= fa.text_field :requester
= fields_for #j_project do |ffa|
= ffa.label :j_login
= ffa.text_field :j_login
= ffa.label :j_password
= ffa.text_field :j_password
= f.submit "Save", class: "btn btn-large btn-primary"
Controller:
class ProjectsController < ApplicationController
def new
#project = Project.new
#p_project = #project.build_p_project
#j_project = #project.build_j_project
end
def create
#project = Project.new(project_params)
#project.user = current_user
#p_project = #project.build_p_project(p_project_params)
#j_project = #project.build_j_project(j_project_params)
if #project.save && #p_project.save && #j_project.save
flash[:success] = "New project was added successfully"
redirect_to user_root_path
else
render 'new'
end
end
private
def project_params
params.require(:project).permit(:title)
end
def p_project_params
params.require(:p_project).permit(:requester)
end
def j_project_params
params.require(:j_project).permit(:j_login, :j_password)
end
end
The problems was with validation:
project_id in j_project and p_project - when I dell them, all works well.
I edit my simple_form and controllers too with guides from internet... But problems, which I cant find in google - was with validation.
The idea is simple. I require a nested attribute tag for user registration. tag requires a user_id.
the view
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: {role: :form}) do |f| %>
<%= f.fields_for :tags, resource.tags.build do |a| %>
<%= a.text_field :tagname %>
<% end %>
<% end %>
tag migration
class CreateTags < ActiveRecord::Migration
def change
create_table :tags do |t|
t.string :tagname
t.references :user, index: true
t.timestamps
end
add_index :tags, :tagname, unique: true
end
end
the tag model
class Tag < ActiveRecord::Base
belongs_to :user
validates_presence_of :user_id
validates_uniqueness_of :tagname
end
the user model
class User < ActiveRecord::Base
has_many :tags, autosave: true, dependent: :destroy
accepts_nested_attributes_for :tags
end
strong parameters
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(
:tags_attributes => [:id, :user_id, :tagname]
) }
The save feature is untouched at the moment. The form passes the nested attribute :tagname just fine. But I've been unable to get the "would be" user_id from resource.
I've already looked for hours online for any answer to this. None has appeared, but the idea that the nested attribute should be saved after the initial user object is saved sounds like a workable solution. But then it's no longer handled as a nested attribute.
Help is appreciated! Thanks!
Solution
Alright I solved it. I bastardised my devise registrations controller a bit, but it works.
First I removed user_id verification from my tag model.
class Tag < ActiveRecord::Base
belongs_to :user
validates_uniqueness_of :tagname
end
I then proceeded with modifying the devise registration controller.
def create
build_resource(sign_up_params)
# added code begins here
#tag = nil
#tag.define_singleton_method(:valid?) {false}
if params["user"].has_key? "tags_attributes"
#tag = Tag.new(params["user"].delete("tags_attributes").values.first)
if #tag.valid?
resource_saved = resource.save # original line of code
else
resource.errors.add(*#tag.errors.first)
flash.delete :tagname_error
set_flash_message :alert, :tag_taken if is_flashing_format?
end
else
set_flash_message :alert, :need_tag if is_flashing_format?
end
# end added code
yield resource if block_given?
if resource_saved
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_flashing_format?
sign_up(resource_name, resource)
# This is where current_user has been created and resource.id == current_user.id
# begin added code
#tag.user_id= resource.id
# end added code
respond_with resource, location: after_sign_up_path_for(resource)
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_flashing_format?
expire_data_after_sign_in!
respond_with resource, location: after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
#validatable = devise_mapping.validatable?
if #validatable
#minimum_password_length = resource_class.password_length.min
end
respond_with resource
end
end
I've defined :tag_taken and :need_tag in my devise locales file for translations of the error string.
And everything works!
For the record this is in addition to the existing code in the question.
I am new with Ruby on Rails. I just build web application on the existing database. I use rails to generate 2 scaffolds for restaurant and location tables. After that I set relationship for these two tables:
class Restaurant < ActiveRecord::Base
attr_accessible :created, :cuisine_fk, :dish_keywords, :dish_names, :factual_id, :first_name, :last_name, :name, :status
has_many :locations
end
class Location < ActiveRecord::Base
attr_accessible :address1, :address2, :city, :created, :latitude, :longitude, :phone, :restaurant_fk, :state, :status, :url, :zip
belongs_to :restaurant
end
I didn't use "rake db:migrate" after I set up this relationship for these tables, because I was afraid that this action would make changes the existing tables.
When I run this command line
<%= restaurant.location.address1%>
it shows error:
undefined method `location'
" NoMethodError in Restaurants#index
Showing C:/Sites/Dishclips/app/views/restaurants/index.html.erb where line #52 raised:
undefined method `location' for #<Restaurant:0x5853bb8> "
After that I tried to set foreign key for the file:
class Location < ActiveRecord::Base
attr_accessible :address1, :address2, :city, :created, :latitude, :longitude, :phone, :restaurant_fk, :state, :status, :url, :zip
belongs_to :restaurant, :class_name => "Restaurant", :foreign_key => 'restaurant_fk'
end
but it still doen't work.
Is there any way that we can set foreign keys in stead of using "rails db:migrate" after we set up the relationships for tables ? I appreciate your help a lot.
The problem is that you are using location wrongly.
Since the restaurant has_many locations you can't use it the way you mentioned. Because you have an array of locations, actually is a ActiveRecord relationship, so in order to access one of the items assciated you'll have to execute the query and get one of the elements. Here is an example of how to get the first element.
restaurant.locations.first.address1
If the restaurant have only one location, than you should change your model to
class Restaurant < ActiveRecord::Base
attr_accessible :created, :cuisine_fk, :dish_keywords, :dish_names, :factual_id, :first_name, :last_name, :name, :status
has_one :locations
end
and access the property as you are doing:
restaurant.location.address1
Also I'm assuming that your database have the columns you specified, otherwise you'll have to run the migrations.
Regards!
Rails associations are covered very well here in the Rails Guides.
I'll walk you through a basic setup here.
$ rails generate model Restaurant name owner ...
$ rails generate model Location restaurant_id:integer city ...
You then need to migrate your database with rake db:migrate for the database table changes to become effective.
The restaurant_id allows us to set the associations in our models as follows
class Restaurant < ActiveRecord::Base
has_many :locations, dependent: :destroy
attr_accessible :name, :owner
end
class Location < ActiveRecord::Base
belongs_to :restaurant
attr_accessible :city # no restaurant_id here
end
Now you can access your restaurants location as follows.
r = Restaurant.create!(name: '...')
l = Location.create!(city: '...')
# Add association
r.locations << l
r.locations will now return an Array with l in it
l.restaurant will return r
Try to play a little with the different styles of associations, for example by creating new Rails apps quickly and just trying some kind of associations, also some that require a join model.
Now I try this way, then it works. Thank you very much.
<td>
<% restaurant.locations.search(params[:restaurant_fk]).each do |location| %>
<!--address = <%= location.address1 %> + " " + <%= location.address2 %>-->
<%= location.address1 %>
<%= location.address2 %> ,
<%= location.city %> ,
<%= location.state %> ,
<%= location.zip %>
<% end %>
</td>