undefined method `addresses' for #<User:0x007fc955029380> - ruby-on-rails

I am new to Ruby and Rails, trying to fix an error I constantly get. Not sure how to fix it. Please help..
Route.rb
namespace :my do
namespace :account do
resource :details, :only => [:show, :update]
resources :addresses
end
end
AddressesController
class My::Account::AddressesController < MyController
def index
#addresses = current_user.addresses
end
def new
#address = current_user.addresses.new
end
....
end
Error - undefined method `addresses'
NoMethodError in My::Account::AddressesController#index
undefined method `addresses' for #<User:0x007fc955029380>
Schema.rb for customer addresses and users
create_table "customer_addresses", force: true do |t|
t.integer "customer_id"
t.string "name"
t.string "line_1"
t.string "line_2"
t.string "line_3"
t.string "line_4"
t.string "line_5"
t.string "postcode"
t.string "phone"
t.datetime "deleted_at"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "customer_addresses", ["customer_id"], name: "index_customer_addresses_on_customer_id"
create_table "users", force: true do |t|
t.string "first_name"
t.string "last_name"
t.string "email"
t.string "password_digest"
t.datetime "created_at"
t.datetime "updated_at"
t.string "password_reset_token"
t.datetime "password_reset_token_at"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
User.rb
class User < ActiveRecord::Base
validates :email, :presence => true, :uniqueness => true
has_secure_password
...
end
Customer.rb
class Customer < User
has_many :addresses
def self.register(attributes)
customer = create!(attributes)
return customer
end
def full_name
"#{first_name} #{last_name}"
end
end
Address.rb
class Customer::Address < ActiveRecord::Base
belongs_to :customer
self.table_name = 'customer_addresses'
default_scope { where(:deleted_at => nil) }
validates :line_1, :postcode, :phone, :presence => true
end

You need to define the relationship on both models.
class User < ActiveRedord::Base
has_many :addresses, class_name: 'CustomerAddress', foreign_key: 'customer_id'
end
class Address < ActiveRecord::Base
belongs_to :user, foreign_key: 'customer_id'
end

Add a #current_customer method to your ApplicationController that return a Customer-instance instead of a User-instance:
class ApplicationController
#…
private
def current_customer
current_user && Customer.find_by_id(current_user.id)
end
end
then change your code like this:
class My::Account::AddressesController < MyController
def index
#addresses = current_customer.addresses
end
def new
#address = current_customer.addresses.new
end
#…
end

Related

ActiveModel::MissingAttributeError (can't write unknown attribute `flights_count`):

I am doing some refactoring and I have seen this project for a while and it worked from what I last recall. But the issue is, I am trying to create a flight and I keep getting "ActiveModel::MissingAttributeError (can't write unknown attribute flights_count):" when trying create a new flight.
As far my models in place:
My Flight, Pilot models
class Flight < ActiveRecord::Base
has_many :passengers
belongs_to :destination
belongs_to :pilot, counter_cache: true
accepts_nested_attributes_for :passengers
belongs_to :user, class_name: "Flight" ,optional: true
validates_presence_of :flight_number
validates :flight_number, uniqueness: true
scope :order_by_flight_international, -> { order(flight_number: :asc).where("LENGTH(flight_number) > 3") }
scope :order_by_flight_domestic, -> { order(flight_number: :asc).where("LENGTH(flight_number) <= 2 ") }
def dest_name=(name)
self.destination = Destination.find_or_create_by(name: name)
end
def dest_name
self.destination ? self.destination.name : nil
end
def pilot_name=(name)
self.pilot = Pilot.find_or_create_by(name: name)
end
def pilot_name
self.pilot ? self.pilot.name : nil
end
end
class Pilot < ActiveRecord::Base
belongs_to :user, optional: true
has_many :flights
has_many :destinations, through: :flights
validates_presence_of :name, :rank
validates :name, uniqueness: true
scope :top_pilot, -> { order(flight_count: :desc).limit(1)}
end
Edit
Flight Controller
class FlightsController < ApplicationController
before_action :verified_user
layout 'flightlayout'
def index
#flights = Flight.order_by_flight_international
#dom_flights = Flight.order_by_flight_domestic
end
def new
#flight = Flight.new
10.times {#flight.passengers.build}
end
def create
#flight = Flight.new(flight_params)
# byebug
if #flight.save!
redirect_to flight_path(current_user,#flight)
else
flash.now[:danger] = 'Flight Number, Destination, and Pilot have to be selected at least'
render :new
end
end
private
def flight_params
params.require(:flight).permit(:flight_number,:date_of_flight, :flight_time, :flight_id, :destination_id, :pilot_id, :pilot_id =>[], :destination_id =>[], passengers_attributes:[:id, :name])
end
end
Edit
Flights, Pilot Schemas
create_table "flights", force: :cascade do |t|
t.integer "pilot_id"
t.integer "destination_id"
t.string "flight_number"
t.string "date_of_flight"
t.string "flight_time"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "pilots", force: :cascade do |t|
t.string "name"
t.string "rank"
t.integer "user_id"
t.integer "flight_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "flight_count", default: 0
end
As I said before when I last worked on this project everything was working fine, but I am faced with this issue. What am I doing wrong this time.
You have defined a counter_cache in your Flight model for pilots. When you just use counter_cache: true to define it, ActiveRecord will look for a column named flights_count in your pilots table but I see that you have named it as flight_count instead. You can either rename the column to flights_count or pass the custom column name to it by using counter_cache: :flight_count
Source https://guides.rubyonrails.org/association_basics.html#options-for-belongs-to-counter-cache

Can't add attribute from another model

I have two models: Account and Profile.
I want render json API with attributes of Profile and include there one attribute from Account.
profile_serializer.rb
class ProfileSerializer < ActiveModel::Serializer
attributes :first_name, :middle_name, :last_name, :role
def role
#UserAccountSerializer.new(object.role)
object.account.role
end
end
account_serializer.rb
class UserAccountSerializer < ActiveModel::Serializer
attributes :role
end
profile.rb
class Profile < Grape::API
desc 'Current user profile'
get '/', serializer: ProfileSerializer do
current_user.profile
end
end
accounts_controller.rb
class AccountsController < AdminController
def index
#accounts = Account.all
end
def show
render json: #account
end
def update
#account = Account.find(params[:id])
redirect_to accounts_path if #account.update(role: params[:role])
end
end
account.rb
class Account < ApplicationRecord
belongs_to :profile
enum role: %i[user admin]
after_initialize :set_default_role, if: :new_record?
def set_default_role
self.role ||= :user
end
end
profile.rb
class Profile < ApplicationRecord
has_one :account
end
schema.rb
create_table "accounts", force: :cascade do |t|
t.string "email", default: "", null: false
t.bigint "profile_id", null: false
t.integer "role", default: 0
t.index ["email"], name: "index_accounts_on_email", unique: true
t.index ["profile_id"], name: "index_accounts_on_profile_id"
end
create_table "profiles", force: :cascade do |t|
t.string "last_name", null: false
t.string "first_name", null: false
t.string "middle_name"
end
Grape give me this error: undefined method `role' for nil:NilClass

How to setup basic Rails models associations?

hey guys im working on a application where a devise user sign ups and logs in, Once the user logs in they can 'create a team' or 'join a team'. I have my associations set up like this
user.rb
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable, :confirmable
validates_presence_of :phone, :city, :state, :street, :zip, presence: true, on: :create
belongs_to :team
end
team.rb
class Team < ApplicationRecord
has_many :users
end
and my tables are set up
schema.rb
create_table "teams", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "team_name"
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "firstname"
t.integer "team_id"
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
team_controller.rb
class TeamController < ApplicationController
before_action :authenticate_user!
def index
#team = current_user.team
end
def new_team
end
def create_team
#team = current_user.create_team(sanitize_team)
if #team.save
redirect_to team_root_path
else
render json: #team.errors.full_messages
end
end
def join_team
#teams = Team.all
end
def team
end
private
def sanitize_team
params.require(:team).permit(:team_name, :team_statement)
end
end
I want the users 'team_id' attribute to update with the teams id when they create a team. or when they join a team. Are my associations correct? how would i make this happen in the controller ?
Yes, associations are correct. You can do it better only by adding foreign key to your database schema. It can be done by generator rails g migration AddTeamToUsers team:references
More information about associations can be found here: https://guides.rubyonrails.org/association_basics.html
In controller you have to change only the whitelisting params to allow team_id. And you probably need to add to your form in view something like this:
<%= f.select :team_id, Team.all.map { |t| [t.team_name, t.id] } %>
Let's strip your code example down to the minimum required:
# app/models/team.rb
class Team < ApplicationRecord
has_many :users
end
# app/models/user.rb
class User < ApplicationRecord
belongs_to :team
end
# db/migrate/20181124230131_create_teams.rb
class CreateTeams < ActiveRecord::Migration[5.2]
def change
create_table :teams do |t|
t.string :team_name
t.timestamps
end
end
end
# db/migrate/20181124230136_create_users.rb
class CreateUsers < ActiveRecord::Migration[5.2]
def change
create_table :users do |t|
t.belongs_to :team
t.timestamps
end
end
end
Then in your controller:
team = Team.where(team_name: 'foo').first_or_create!
team.users << current_user
Start by setting the association up as optional:
class User < ApplicationController
belongs_to :team, optional: true
end
Otherwise the validations on the user model will not let the user be saved without a team.
Then setup the teams resource:
# config/routes.rb
resources :teams do
post :join
end
post :join creates an additional POST /teams/:team_id/join route.
Then setup the controller:
class TeamsController
# ...
# GET /teams/new
def new
#team = Team.find
end
# POST /teams
def create
#team = Team.new(team_params)
if #team.save
unless current_user.team
current_user.update(team: #team)
end
redirect_to 'somewhere'
else
render :new
end
end
# ...
def join
#team = Team.find(params[:team_id])
if current_user.update(team: #team)
redirect_to #team, notice: 'Team joined'
else
redirect_to #team, error: 'Could not join team'
end
end
#
private
def team_params
params.require(:team).permit(:team_name, :team_statement)
end
end
Note that prefixing your action names is neither needed nor compatible with the "Rails way". Prefixing column names is also largely superfluous.

Rails - Creating a belongs_to association between models prevents me from editing the model

I'm trying to create an association between two models in my Rails app (User and Coin) where Coin belongs_to User and User has_many Coins. When I add the belongs_to association in the Coin model, I am no longer able to edit or create Coin pages. Why would it do this? As soon as I remove the association, I'm able to create/edit again. Also, the corresponding has_many association on the User page does not have the same effect. I'd appreciate any help in understanding what is happening here and how I can properly make this association. Thanks.
User.rb
class User < ApplicationRecord
acts_as_votable
has_many :questions, dependent: :destroy
has_many :events, dependent: :destroy
has_many :links, dependent: :destroy
has_many :posts, dependent: :destroy
has_many :moderated_coins, class_name: "Coin"
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable,
:validatable, authentication_keys: [:login]
validates :username, presence: :true, uniqueness: { case_sensitive: false }
validates_format_of :username, with: /^[a-zA-Z0-9_\.]*$/, :multiline => true
validate :validate_username
def validate_username
if User.where(email: username).exists?
errors.add(:username, :invalid)
end
end
def login=(login)
#login = login
end
def login
#login || self.username || self.email
end
def self.find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
where(conditions.to_h).where(["lower(username) = :value OR lower(email) = :value", { :value => login.downcase }]).first
elsif conditions.has_key?(:username) || conditions.has_key?(:email)
where(conditions.to_h).first
end
end
end
Coin.rb
class Coin < ApplicationRecord
validates :currency_name, presence: true
has_many :questions, dependent: :destroy
has_many :events, dependent: :destroy
has_many :links, dependent: :destroy
mount_uploader :picture, PictureUploader
has_and_belongs_to_many :genres
# belongs_to :moderator, class_name: "User". <--- * The problem is here
validate :picture_size
private
def picture_size
if picture.size > 5.megabytes
errors.add(:picture, "Picture must be smalled than 5MB.")
end
end
end
coins_controller.rb
class CoinsController < ApplicationController
load_and_authorize_resource param_method: :question_params
before_action :find_coin, only: [:edit, :update, :destroy ]
before_action :authenticate_user!, except: [:index, :create, :show]
def index
#search = Coin.ransack(params[:q])
#coins = #search.result(distinct: true)
end
def new
#coin = Coin.new
end
def create
#coin = Coin.new(coin_params)
if #coin.save
flash[:success] = "Coin created"
redirect_to #coin
else
render 'new'
end
end
def show
#coin = Coin.find(params[:id])
end
def edit
authorize! :update, #coin
end
def update
if #coin.update(coin_params)
redirect_to #coin
else
render 'edit'
end
end
def destroy
Coin.find(params[:id]).destroy
redirect_to coins_url
end
private
def coin_params
params.require(:coin).permit( :currency_name, :currency_abbrev, :moderator_id, :accepted, :picture, :question1, :question2, :question3, :question4, genre_ids:[])
end
def find_coin
#coin = Coin.find(params[:id])
end
end
user_controller.rb
class UsersController < ApplicationController
before_action :authenticate_user!
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #user }
end
end
end
schema.rb
create_table "coins", force: :cascade do |t|
t.string "link_name"
t.string "currency_name"
t.string "currency_abbrev"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "permalink"
t.boolean "accepted", default: false
t.datetime "accepted_at"
t.string "genre"
t.integer "genre_id"
t.integer "moderator_id"
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
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.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "username"
t.string "wallet"
t.boolean "admin", default: false
t.boolean "moderator", default: false
t.decimal "currentbalance", precision: 8, scale: 2
t.decimal "payout_to_date", precision: 8, scale: 2
t.text "bio"
t.string "link1"
t.string "link2"
t.string "link3"
t.string "link4"
t.string "link5"
t.string "name"
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
t.index ["username"], name: "index_users_on_username", unique: true
end
Use:
belongs_to :moderator, class_name: "User", optional: true
In rails 5, belongs_to enforces existence of the associated record by default. You need to use optional: true in order to allow moderator_id to be nil.

Association problems in between models RAILS 4

My models
CAR BRANDS MODEL
class CarBrand < ActiveRecord::Base
has_many :car_ads
end
CAR ADVERTISEMENTS MODEL
class CarAd < ActiveRecord::Base
has_one :car_brand
end
my controller:
def index
#car_ads = CarAd.all.order("car_ads.created_at DESC")
end
car ads migrations:
class CreateCarAds < ActiveRecord::Migration
def up
create_table :car_ads do |t|
t.integer "user_id"
t.integer "car_brand_id"
t.integer "car_model_id"
t.integer "state_id", :limit => 2
t.integer "vin_id"
t.integer "year_manufac", :precision => 4
t.integer "km_age"
t.integer "price_usd", :limit => 7
t.integer "car_tel_number", :precision => 8
t.float "motor_volume", :limit => 10
t.string "transmission"
t.integer "horse_power", :limit => 3
t.text "description"
t.boolean "visible", :default => true
t.boolean "active", :default => true
t.string "photo_file_name"
t.string "photo_content_type"
t.integer "photo_file_size"
t.datetime "photo_updated_at"
t.timestamps null: false
end
add_index :car_ads, :user_id
add_index :car_ads, :car_brand_id
add_index :car_ads, :car_model_id
add_index :car_ads, :state_id
add_index :car_ads, :vin_id
end
def down
drop_table :car_ads
end
end
Car brands migratiions
class CreateCarBrands < ActiveRecord::Migration
def up
create_table :car_brands do |t|
t.string "brand", :limit => 20
t.timestamps null: false
end
end
def down
drop_table :car_brands
end
end
so the problem is that i cant get car brand form car ads, please help,
i wanted to get that like
iterating
<% #car_ads.each do |carad|%>
<%= carad.car_brand %>
<%end%>
Modify CAR ADVERTISEMENTS MODEL
class CarAd < ActiveRecord::Base
belongs_to :car_brand
end
Modify your controller:
def index
#car_ads = CarAd.all.order("created_at DESC")
end
You didn't add any reference to CarBrand in CarAd table, just add the car_ad_id column with a migration like this
class AddCarBradIdToCarAd < ActiveRecord::Migration
def change
add_column :car_ads, :car_brand_id, :integer
end
end
So rails would be able to get the corresponding CarBrand from a CarAd

Resources