def destroy
#dignity.destroy
end
Sorry, that's not code, that's just how I feel right now. I know there are a ton of beginner questions on Devise, I think I looked at almost every single one.
I have a very simple Devise setup in Rails 3. I did:
rails generate devise User
I'm also running the rails 3 GeoKit plugin,(not sure if that's relevant, just know that I have this other model) so I have another model called Location, and it acts_as_mappable.
Before I post the code, the basic problem is that I cannot seem to get user_id to auto-increment. It was my understanding that a bit of Rails magic should take care of this for me, if I add a column called user_id to Location class. (which I did through a migration.) and then simply set has_many and belongs_to accordingly. (see below)
I can't figure out why user_id is always nil. Does it have something to do with the way the Devise engine works? I am pretty sure I've made this type of association work in the past in the same way when I wasn't using Devise.
user.rb:
class User < ActiveRecord::Base
has_many :locations
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable, :lockable and :timeoutable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
end
location.rb:
class Location < ActiveRecord::Base
belongs_to :user
attr_accessible :street_adress, :city, :state, :zip, :item, :user_id
acts_as_mappable :auto_geocode => true
def address
return "#{self.street_adress}, #{self.city}, #{self.state}, #{self.zip}, #{self.item}"
end
end
here is the migration that added the column:
class AddUseridToLocation < ActiveRecord::Migration
def self.up
add_column :locations, :user_id, :integer
end
def self.down
remove_column :locations, :user_id
end
end
And finally, here is the schema.rb:
ActiveRecord::Schema.define(:version => 20110213035432) do
create_table "locations", :force => true do |t|
t.string "street_adress"
t.string "city"
t.string "state"
t.string "zip"
t.float "lat"
t.float "lng"
t.datetime "created_at"
t.datetime "updated_at"
t.string "item"
t.integer "user_id"
end
create_table "users", :force => true do |t|
t.string "email", :default => "", :null => false
t.string "encrypted_password", :limit => 128, :default => "", :null => false
t.string "password_salt", :default => "", :null => false
t.string "reset_password_token"
t.string "remember_token"
t.datetime "remember_created_at"
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.datetime "created_at"
t.datetime "updated_at"
end
add_index "users", ["email"], :name => "index_users_on_email", :unique => true
add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
end
EDIT: I'm okay with a RTFM response, as long as I can get a little push in the right direction. I have a suspicion that I need to tell rails something in the create action of my locations_controller.rb ? Someone just give me a little hint here!
def destroy
#dignity.destroy
end
Clearly the first thing to be done is:
raise self.esteem
You say you can't get user_id to "autoincrement". I think what you meant is that user_id is not being assigned (i.e. it is always nil). Can you show the part of the code that assigns a location to a user? Either of these should work:
#user.locations.build
#user.locations << Location.new
EDIT
To expand on this a bit, say you have a request that looks like this:
POST /users/37/locations
And the submitted form contains input name=user[location][name] value="Paris". A typical Rails controller create action might look like this:
def create
#user = User.find(params[:user_id])
#user.locations.build(params[:user][:location])
if #user.save
flash[:notice] = "Location created successfully"
redirect_to user_locations_path(#user)
else
render :new
end
end
The 'magic' is basically Rails inferring from the has_many statement that it needs to set the value of the foreign key column ('user_id') in the related row in the locations table. When you call #user.save it adds a new row in locations and sets user_id to the value of #user.id.
Related
So I have the following functionality where I have courses, course modules and course exercises.
I have it where users can mark off modules once completed when all modules are completed the course gets set to complete.
However, this is applying to all users, not individual users. So, for example, what is currently happening is that one user completes the course and when it's being marked as complete but if I sign in as a second user (who hasn't completed the course) it's being marked as complete.
From my research, I believe I could achieve this using a has_many_through association, but I'm unsure how to set this up.
Here is how I have things set up so far.
schema.rb
create_table "course_exercises", force: :cascade do |t|
t.string "title"
t.text "description"
t.string "video"
t.integer "course_module_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "slug"
t.index ["course_module_id"], name: "index_course_exercises_on_course_module_id"
t.index ["slug"], name: "index_course_exercises_on_slug", unique: true
end
create_table "course_modules", force: :cascade do |t|
t.string "title"
t.integer "course_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "slug"
t.boolean "complete", default: false, null: false
t.index ["course_id"], name: "index_course_modules_on_course_id"
t.index ["slug"], name: "index_course_modules_on_slug", unique: true
end
create_table "courses", force: :cascade do |t|
t.string "title"
t.text "summary"
t.text "description"
t.string "trailer"
t.integer "price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "slug"
t.boolean "complete", default: false, null: false
t.index ["slug"], name: "index_courses_on_slug", unique: true
end
user.rb
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
has_one_attached :avatar
has_many :courses
def after_confirmation
welcome_email
super
end
protected
def welcome_email
UserMailer.welcome_email(self).deliver
end
end
course.rb
class Course < ApplicationRecord
extend FriendlyId
friendly_id :title, use: :slugged
has_many :users
has_many :course_modules
validates :title, :summary, :description, :trailer, :price, presence: true
def complete!
update_attribute(:complete, true)
end
end
course_module.rb
class CourseModule < ApplicationRecord
extend FriendlyId
friendly_id :title, use: :slugged
belongs_to :course
has_many :course_exercises
validates :title, :course_id, presence: true
scope :completed, -> { where(complete: true) }
after_save :update_course, if: :complete?
private
def update_course
course.complete! if course.course_modules.all?(&:complete?)
end
end
Completed modules
Completed course
Databases:
Course
Course Modules
But as I mentioned above, it's getting assigned to all users, not individual users.
Any help here is appreciated.
As per the description it seems like you will be needing another table to
capture the data user wise to show completed modules.
But another catch here is that you will also be needing to capture the progress
of course_exersises a particular user has completed so that after completing
all the exercises you can update the course_module.
Note: Entery in below mentioned table in done only when a user has completed the
given exercise, also we will be having the timestamp as provided by rails.
User
has_many :courses, through: :user_courses
has_many :exercises, through: :user_course_exercise
UserCourseExercise
belongs_to :user
belongs_to :course_exercise
#table columns
user_id
exercise_id
Entry in this table will be done if all the exercises of a particular course has
been completed.
UserCourse
belongs_to :user
belongs_to :course_exercise
#table columns
user_id
course_id
The approach of having two tables would be that when you need to show the exercise
data corresponing to a particular user then you will be using user_course_exercise
and when completed courses are needed then usign the user_course table
I'm new to development, and have spent the last 12 hours (literally) trying to figure out this error message - I'm giving up for the night, but not before a quick cry for help to stackoverflow.
I have this form:
<h2>Select from the language options below (or, <%= button_to "Login", 'users/login', method: :get %></h2>
<%= form_for #language_role do |f| %>
<div id="input">
<h3>I want to learn:</h3><%= select_tag(:language_id, options_from_collection_for_select(Language.all, :id, :lang_name)) %>
</div>
<div>
<p><%= f.submit "Start learning" %></p>
</div>
<% end %>
which is giving me this error message, highlighting the line #language_role = current_user.language_roles.build : "undefined method `language_roles' for nil:NilClass"
I have three tables:
create_table "language_roles", force: :cascade do |t|
t.integer "language_id"
t.boolean "is_active"
t.boolean "is_teacher"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.index ["user_id"], name: "index_language_roles_on_user_id"
end
create_table "languages", force: :cascade do |t|
t.string "lang_name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
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.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
The language_roles table is meant to allow a user to have many languages, as well as many roles within that language. Here are my class definitions:
class LanguageRole < ApplicationRecord
belongs_to :languages
belongs_to :users
end
class Language < ApplicationRecord
has_many :language_roles
has_many :users, :through => :language_roles
end
class User < ApplicationRecord
has_many :language_roles
has_many :languages, :through => :language_roles
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
My root path goes to 'home#index', where the user is supposed to pick a language if current_user.language_roles is empty. As such, I put this code in my home controller and language_roles controller:
class HomeController < ApplicationController
def index
#language_role = current_user.language_roles.build
end
end
class LanguageRolesController < ApplicationController
def create
#language_role = current_user.language_roles.build(language_role_params)
if #language_role.save
redirect_to root_path
else
redirect_to :back
end
end
private
def language_role_params
params.permit(:language_id)
end
end
What in the hell is the problem?? I assume I need to instantiate the variable somehow, but I'm not sure how.
Thanks,
Michael
There is a typo in your LanguageRole Model:
LanguageRole < ApplicationRecord
belongs_to :languages
belongs_to :users
end
should be
LanguageRole < ApplicationRecord
belongs_to :language
belongs_to :user
end
belongs_to associations must use the singular term.
The name of the other model is pluralized when declaring a has_many association.
Ref: http://guides.rubyonrails.org/association_basics.html
Your current_user is not defines it seems. You can install a gem called 'pry-rails' and debug your way out of this situation and any other in future. Here's a tutorial how to use it Railscasts #280
In your LanguageRole model you defined like belongs_to :users. But it should be belongs_to :user.
Your model look like ...
LanguageRole < ApplicationRecord
belongs_to :languages
belongs_to :users
end
Which should be something like
LanguageRole < ApplicationRecord
belongs_to :language
belongs_to :user
end
I am unable to find accurate information to what I want, so my second choice is to ask.
So, I want to know how to create a user profile from scratch and with your username replacing the ID.
Example: http://example.com/profile/{username}
In this case I have no problems with usernames, as are those working on a game server and they can not contain spaces or unusual characters.
I have done something, but I think it is wrong, even though I do not have any error on my website.
Notes:
My Devise Model: Player/s
Schema of Players
create_table "players", 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"
t.datetime "updated_at"
t.boolean "admin", default: false
t.integer "role_id"
t.string "nick"
t.string "username"
end
Variables "admin and role_id" are for charges will have on the web. I think this is not relevant to the subject.
Looked at other tutorials, but I have no more special things to add to my code.
My Controllers:
- registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
protected
def after_sign_up_path_for(resource)
new_path(resource)
end
end
profile_controller.rb
class ProfileController < ApplicationController
def members
end
def myProfile
#attributes = Profile.attribute_names - %w(id player_id created_at updated_at)
end
def new
#profile = current_player.build_profile
end
def create
#profile = current_player.build_profile(params[:profile].permit( :nick))
end
end
My Models:
- player.rb
class Player < ActiveRecord::Base
validates :email, :presence => true, :email => true
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
belongs_to :role
before_create :set_default_role
has_one :profile
private
def set_default_role
self.role ||= Role.find_by_name('registered')
end
end
profile.rb
class Profile < ActiveRecord::Base
belongs_to :players
end
And in my view, have the controller profiles with:
myProfile => Only the profile of the user
profiles that is the global view of the profiles
route.rb
get 'profile/:id' => 'profile#perfiles'
resources :profile, only: [:edit]
map.resources :players, :has_one => :profile
map.resources :profiles
I hope I'm not asking for much, but hey, it's a question that I have and worth a try.
Thanks in advance, if anything is missing tell me.
I believe what you're looking to do is override the named route parameter. See this rails guide for more details: http://edgeguides.rubyonrails.org/routing.html (section 4.10).
Basically, you'll want to just add the param: :username to your routes file:
resources :profile, only: [:edit], param: :username
Which will make your route look something like:
profile GET /profile/:username(.:format) profile#show
And in your controller:
#profile = Profile.find_by(username: params[:username])
Hope that helps!
I am trying to create a view for photo uploads for users. I'm new to rails so I'm not quite sure if I am doing this correctly because I'm not quite sure how all the pieces fit. I am using devise and also carrierwave for user authentication and image storage in database. I'm not quite sure what to do with the params for IncomePicture_params. I want to create a view that will allow me to call and display the images and the texts for pictures of the user
I am using rails 4
Models:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:rememberable, :validatable
validates_presence_of :username
has_many :expense_pictures
has_many :income_pictures
end
class IncomePicture < ActiveRecord::Base
belongs_to :user
mount_uploader :image, ImageUploader
has_one :income_text
accepts_nested_attributes_for :income_text
end
class IncomeText < ActiveRecord::Base
belongs_to :income_picture
end
controller:
class UserController < ApplicationController
def create
User.create(user_params)
end
private
def user_params
# required input for params
# permit - returns a version of the params hash with ony the permitted attributes
params.require(:user).permit(:name, :email, :password, :password_confirmation, )
end
end
class IncomePicturesController < ApplicationController
def new
#income_picture = IncomePicture.new(IncomePicture_params)
end
def create
end
def destroy
end
private
def IncomePicture_params
params.require(:income_picture).permit(:image, income_text_attributes: [:amount])
end
end
schema
ActiveRecord::Schema.define(version: 20140723044409) do
create_table "income_pictures", force: true do |t|
t.datetime "created_at"
t.datetime "updated_at"
t.string "image"
t.integer "user_id"
end
add_index "income_pictures", ["user_id"], name: "index_income_pictures_on_user_id"
create_table "income_texts", force: true do |t|
t.datetime "created_at"
t.datetime "updated_at"
t.integer "income_picture_id"
t.string "amount"
end
add_index "income_texts", ["income_picture_id"], name: "index_income_texts_on_income_picture_id"
create_table "users", force: true do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.datetime "remember_created_at"
t.datetime "created_at"
t.datetime "updated_at"
t.string "username"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
end
I am using authlogic to do my authentication. The current model that serves as the authentication model is the user model. I want to add a "belongs to" relationship to user which means that I need a foreign key in the user table. Say the foreign key is called car_id in the user's model. However, for some reason, when I do
u = User.find(1)
u.car_id = 1
u.save!
I get
ActiveRecord::RecordInvalid: Validation failed: Password can't be blank
My guess is that this has something to do with authlogic. I do not have validation on password on the user's model. This is the migration for the user's table.
def self.up
create_table :users do |t|
t.string :email
t.string :first_name
t.string :last_name
t.string :crypted_password
t.string :password_salt
t.string :persistence_token
t.string :single_access_token
t.string :perishable_token
t.integer :login_count, :null => false, :default => 0 # optional, see Authlogic::Session::MagicColumns
t.integer :failed_login_count, :null => false, :default => 0 # optional, see Authlogic::Session::MagicColumns
t.datetime :last_request_at # optional, see Authlogic::Session::MagicColumns
t.datetime :current_login_at # optional, see Authlogic::Session::MagicColumns
t.datetime :last_login_at # optional, see Authlogic::Session::MagicColumns
t.string :current_login_ip # optional, see Authlogic::Session::MagicColumns
t.string :last_login_ip # optional, see Authlogic::Session::MagicColumns
t.timestamps
end
end
And later I added the car_id column to it.
def self.up
add_column :users, :user_id, :integer
end
Is there anyway for me to turn off this validation?
Sure. Per the docs:
acts_as_authentic do |c|
c.ignore_blank_passwords = true
end