NoMethodError (undefined method `each' for "0":String) - ruby-on-rails

Rails 5.1
My migration file:
class CreateFwExports < ActiveRecord::Migration[5.1]
def change
create_table :fw_exports, id: :string do |t|
t.string :screen_name, index: true, limit: 16
t.string :full_name, limit: 21
t.string :location_placeholder
t.timestamps
end
end
end
From the fw_exports controller:
def fw_export_params
params.require(:fw_export).permit(:screen_name, :full_name, :location_placeholder)
end
In the fw_export.rb model, I have:
has_one :location
has_many :followers
In the location.rb model, I have:
belongs_to :fw_export
In the follower.rb model, I have:
has_many :followed
In my helper file, I have the following method:
def process_spreadsheet(number_of_rows, spreadsheet, followed_id)
(1..number_of_rows).each do |i|
fw_export_record = FwExport.new(
:screen_name => spreadsheet[i][0],
:full_name => spreadsheet[i][1],
:location_placeholder => spreadsheet[i][2],
)
fw_export_record.save
location = Location.new(
:fw_exports_id => fw_export_record.id
)
location.save
follower = Follower.new(
:followed_id => followed_id,
:fw_exports_id => fw_export_record.id
)
follower.save
end
end
What this method does, is receive a spreadsheet CSV object, and iterates through the data, trying to save each row to the fw_exports table. It also creates entries into the locations and followers tables
There is a locations table, with the following fields:
t.string :fw_exports_id, index: true
t.string :city
t.string :state
t.string :country
and a followers table with the following fields:
t.string :followed_id
t.string :fw_exports_id
t.string :slug, index: true
When I try to import the data, I get the following error:
NoMethodError (undefined method `each' for "0":String):
app/helpers/fw_exports_helper.rb:21:in `block in process_spreadsheet'
app/helpers/fw_exports_helper.rb:20:in `process_spreadsheet'
app/controllers/fw_exports_controller.rb:82:in `process_parsed_spreadsheet'
I verified that all the parameters passed to the process_spreadsheet call are valid.
Any ideas?

Related

ArgumentError: wrong number of arguments (3 for 0) when adding like, favorite and inappropriate button to microposts with make_flaggable gem

I want to add like, favorite and inappropriate button to microposts.
User can like a micropost only one time. But also user who likes the micropost can click the favorite button.
When I tried that in rails console I've an error.
Error
irb(main):002:0> micropost=Micropost.first
ArgumentError: wrong number of arguments (3 for 0)
from /Users/tanerkoroglu/.bundler/ruby/2.0.0/make_flaggable-99297edddfec/lib/make_flaggable.rb:22:in `make_flaggable'
from /Users/tanerkoroglu/Desktop/Wishpere2/app/models/micropost.rb:9:in `<class:Micropost>'
from /Users/tanerkoroglu/Desktop/Wishpere2/app/models/micropost.rb:1:in `<top (required)>'
from /Library/Ruby/Gems/2.0.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:457:in `load'
micropost.rb
make_flaggable :like, :inappropriate, :favorite
user.rb
make_flagger :flag_once => true
create_make_flaggable_tables.rb
class CreateMakeFlaggableTables < ActiveRecord::Migration
def self.up
create_table :flaggings do |t|
t.string :flaggable_type
t.integer :flaggable_id
t.string :flagger_type
t.integer :flagger_id
t.text :reason
t.timestamps
end
add_index :flaggings, [:flaggable_type, :flaggable_id]
add_index :flaggings, [:flagger_type, :flagger_id, :flaggable_type, :flaggable_id], :name => "access_flaggings"
end
def self.down
remove_index :flaggings, :column => [:flaggable_type, :flaggable_id]
remove_index :flaggings, :name => "access_flaggings"
drop_table :flaggings
end
end
create_microposts.rb
class CreateMicroposts < ActiveRecord::Migration
def change
create_table :microposts do |t|
t.text :content
t.references :user, index: true, foreign_key: true
t.timestamps null: false
end
add_index :microposts, [:user_id, :created_at]
end
end
add_flaggings_count_to_microposts.rb
class AddFlaggingsCountToMicroposts < ActiveRecord::Migration
def change
add_column :microposts,:flaggings_count, :integer
end
end
add_flaggings_count_to_users.rb
class AddFlaggingsCountToUsers < ActiveRecord::Migration
def change
add_column :users, :flaggings_count, :integer
end
end
First of all make_flaggable method doesn't accept any parameter as mentioned in the source code here and that's why you see 3 for 0 argument error.
You don't have to pass any argument to make_flaggable in your model.
micropost.rb
make_flaggable
By default, the model becomes flaggable by any other model.
If you want it to be flaggable by models where it has been marked as flagger. Then you can restrict micropost be flagged only by those models which are marked as flagger.
micropost.rb
make_flaggable :once_per_flagger => true
So for your model, don't pass any parameter to make_flaggable.

undefined method `<<' for nil:NilClass rails console

Hey i'm creating database schema and test it in rails console. I have relation User has_many :rates and Rates belongs_to :user. When I type in rails console:
user = User.find(1)
rate = Rate.find(1)
user.rates << rate
Every thing works fine, but when i want to do it in opposite way:
user2 = User.find(2)
rate2 = Rate.find(2)
rate2.user << user2
I've got an following error NoMethodError: undefined method `<<' for nil:NilClass
Users Migration
class CreateUsers < ActiveRecord::Migration
def up
create_table :users do |t|
t.column "username", :string, :limit => 25
t.string "first_name", :limit => 30
t.string "last_name", :limit => 50
t.string "password"
t.date "date_of_birth"
t.timestamps
end
end
end
Rates Migration
class CreateRates < ActiveRecord::Migration
def change
create_table :rates do |t|
t.integer "user_id"
t.integer "credibility", :limit => 1 #0 or 1
t.timestamps
end
add_index("rates", "user_id")
end
end
The user attribute is not an array (or collection of any kind), you must assign to it.
user2 = User.find(2)
rate2 = Rate.find(2)
rate2.user = user2

Rails - has_many relation causes NoMethodError

I've the following migrations and models:
class CreatePlatforms < ActiveRecord::Migration
def change
create_table :platforms do |t|
t.integer :user_id
t.string :name
t.string :platform_id
t.timestamps
end
end
end
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :email
t.string :first_name
t.string :last_name
t.string :gender
t.date :birthday
t.timestamps
end
end
end
class Platform < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
attr_accessible :email, :first_name, :last_name, :gender, :birthday
has_many :platforms
end
With this definition I can create users and platforms:
user = User.new
platform1 = Platform.new
platform2 = Platform.new
And even I can associate users to platforms:
platform1.user = user
But when I try to associate platforms to users or get the platforms from a users it crashes:
user.platforms << user or user.platforms
NoMethodError: undefined method `platforms' for #<User:0x007f8cfd47a770>
As it turns out, the problem is the database field platform_id. This messes up rails. Simply delete it and it'll work.

whats wrong with my collection_select in my sign up view page

I am newbie to rails ,
I am using devise from ryan bates video tutorial , and , i am stuck at one point
I have created user , role relationship
and in the sign up page , i need to provide select option group for existing roles ,
in my sign up view page i am writing
<%= collection_select(:user,:roles,Role.find(:all),:id,:name) %>
i dont precisely understand collection_select method , kindly help what i might be doing wrong
my models 1 : user.rb
class User < ActiveRecord::Base
has_and_belongs_to_many :roles
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :remember_me , :roles
has_and_belongs_to_many :roles
def role?(role)
return !!self.roles.find_by_name(role.to_s.camelize)
end
end
my model 2 : role.rb
class Role < ActiveRecord::Base
attr_accessible :name
has_and_belongs_to_many :users
end
my user migration file
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
## Database authenticatable
t.string :email, :null => false, :default => ""
t.string :encrypted_password, :null => false, :default => ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, :default => 0
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
t.timestamps
end
add_index :users, :email, :unique => true
add_index :users, :reset_password_token, :unique => true
end
end
my role migration file
class CreateRoles < ActiveRecord::Migration
def change
create_table :roles do |t|
t.string :name
t.timestamps
end
end
end
my join table migration file
class UsersHaveAndBelongToManyRoles < ActiveRecord::Migration
def up
create_table :roles_users, :id => false do |t|
t.references :role, :user
end
end
def down
drop_table :roles_users
end
end
the ERROR COMING is
undefined method `each' for "2":String
2 being the id of the role selected
In a has_and_belongs_to_many relationship like you have between User and Role, there is no role_id on the User object.
The second parameter of the collection_select is the attribute you're updating with the selection(s), in your case it's not role_id, it's role_ids and seeing as it's a has_and_belongs_to_many relationship you probably want to allow the user to select multiple options, so try something like this:
<%= collection_select(:user, :role_ids, Role.all, :id, :name, {}, { selected: #user.role_ids, multiple: true }) %>
If you attach it to a form_for on your #user object you can use:
<%= f.collection_select(:role_ids, Role.all, :id, :name, {}, multiple: true) %>

STI and has_many association with "type" column as Key

I am using Single Table Inheritance for managing different types of projects.
I decided to store some information associated with each project type. So i created new table "project_types" with "model_type" field as primary key. Primary key values are values of "type" field of "projects" table. Problem: When i trying to get associated with Project object ProjectTypes object it always returns null.
>> p = Project.find(:first)
=> #<SiteDesign id: 1, type: "SiteDesign", name: "1", description: "dddd", concept: "d", client_id: 40, created_at: "2009-10-15 08:17:45", updated_at: "2009-10-15 08:17:45">
>> p.project_type
=> nil
Getting projects associated with ProjectTypes project is OK. Is there way to make it works properly?
Models:
class Project < ActiveRecord::Base
belongs_to :project_type, :class_name => "ProjectTypes", :foreign_key => "model_name"
end
class SiteDesign < Project
end
class TechDesign < Project
end
class ProjectTypes < ActiveRecord::Base
self.primary_key = "model_name"
has_many :projects, :class_name => "Project", :foreign_key => "type"
end
Migrations:
class CreateProjectTypes < ActiveRecord::Migration
def self.up
create_table :project_types, :id => false do |t|
t.string :model_name , :null => false
t.string :name, :null => false
t.text :description
t.timestamps
end
add_index :project_types, :model_name, :unique => true
#all project types that are used.
models_names = {"SiteDesign" => "Site design",
"TechDesign" => "Tech design"}
#key for model_name and value for name
models_names.each do |key,value|
p = ProjectTypes.new();
p.model_name = key
p.name = value
p.save
end
end
def self.down
drop_table :project_types
end
end
class CreateProjects < ActiveRecord::Migration
def self.up
create_table :projects do |t|
t.string :type
t.string :name
t.text :description
t.text :concept
t.integer :client_id
t.timestamps
end
end
def self.down
drop_table :projects
end
end
Not surprising you're getting problems. By moving from a pure STI system to your current system you are horribly breaking the patterns you are using by intermingling parts of one with parts of another.
I'd personally go for something like:
class Project < ActiveRecord::Base
attr_readonly(:project_type)
belongs_to :project_type
before_create :set_project_type
def set_project_type()
project_type = ProjectType.find_by_model_name(this.class)
end
end
class SiteProject < Project
end
class TechProject < Project
end
class ProjectType < ActiveRecord::Base
has_many :projects
end
with migrations:
class CreateProjectTypes < ActiveRecord::Migration
def self.up
create_table :project_types do |t|
t.string :model_name , :null => false
t.string :name, :null => false
t.text :description
t.timestamps
end
add_index :project_types, :model_name, :unique => true
#all project types that are used.
models_names = {"SiteDesign" => "Site design",
"TechDesign" => "Tech design"}
#key for model_name and value for name
models_names.each do |key,value|
p = ProjectTypes.new();
p.model_name = key
p.name = value
p.save
end
end
def self.down
drop_table :project_types
end
end
class CreateProjects < ActiveRecord::Migration
def self.up
create_table :projects do |t|
t.string :type
t.references :project_type, :null => false
t.text :description
t.text :concept
t.integer :client_id
t.timestamps
end
end
def self.down
drop_table :projects
end
end
It just cleans things up and it also helps clarify what you're doing. Your 'ProjectType' table is purely for extra data, your inheritance tree still exists. I've also thrown in some checks to make sure your project type is always set (and correctly, based on the model name) and stops you from changing project type once it's been saved by making the attribute read only.

Resources