track model not being created in my rails app - ruby-on-rails

in my rails app, I am running into an issue. As a heads up I am using devise.
tracks_controller.rb
def new
#track = Track.new
end
def create
#track = current_user.tracks.build(params[:content])
if #track.save
flash[:success] = "Track created!"
redirect_to #user
else
render 'static_pages/home'
end
users_controller.rb
def show
#user = User.find(params[:id])
#tracks = #user.tracks
if signed_in?
#track = current_user.tracks.build
end
end
I am logged in as a current user, and when I try to add a new track (through the current user) it is not saving.. (and instead redirects to root_url)
track.rb
class Track < ActiveRecord::Base
attr_accessible :content
belongs_to :user
end
user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :username, :email, :password, :password_confirmation, :remember_me
# attr_accessible :title, :body
validates :username, uniqueness: { case_sensitive: false }
has_many :tracks, dependent: :destroy
end
shared/_track_form.html.erb
<%= form_for(#track) do |f| %>
<div class="track_field">
<%= f.text_area :content, placeholder: "Upload a youtube song URL...", :id => "message_area" %>
</div>
<%= f.submit "Post", class: "btn btn-large btn-primary" %>
relavent section for /users/show.html.erb
<div class="span8">
<% if signed_in? %>
<section>
<%= render 'shared/track_form' %>
</section>
<% end %>
I believe the issue is in my TracksController #create method, however I just can't figure it out. any help is greatly appreciated, thanks!

In your controller create action change
#track = current_user.tracks.build(params[:content])
to this
#track = current_user.tracks.build(params[:track])
Since you used form_for(#track) the params hash will contain the :content field filled into the form.
The way you have it now the create action cant find the form :content because there isn't a form named content. content is an attribute of the Track model.

Related

Rails 5 - Devise - User has_one association - nested form fields are not shown at sign up form

As I searched, this is a common issue, but none of the answers I found work for my case.
I have set up a User model with devise and it has two related models, it has one Contact Detail and many Addresses. The nested form works well with addresses, but my contact detail fields are not shown.
My User model is the following:
validates_presence_of :contact_detail, :addresses
# Include default devise modules. Others available are:
# :lockable, :timeoutable, :trackable and :omniauthable
devise :invitable, :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable, :confirmable
has_one :contact_detail, dependent: :destroy
has_many :addresses, dependent: :destroy
accepts_nested_attributes_for :addresses,
allow_destroy: true
accepts_nested_attributes_for :contact_detail,
allow_destroy: true
The contact details model only has belongs_to :user
I made the changes mentioned at devise gem at my application controller:
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [addresses_attributes: [:street_name, :street_number, :city, :country, :postal_code, :name],
contact_detail_attributes: [:first_name, :last_name, :description, :telephone, :mobile ]])
end
end
and my app/views/devise/registrations/new.html.erb file looks like this:
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
...
<div>
<% f.fields_for :contact_detail do |contact_detail|%>
<div class="field">
<%= contact_detail.label :first_name %>
<%= contact_detail.text_field :first_name %>
</div>
<div class="field">
<%= contact_detail.label :last_name %>
<%= contact_detail.text_field :last_name %>
</div>
<div class="field">
<%= contact_detail.label :description %>
<%= contact_detail.text_area :description %>
</div>
<div class="field">
<%= contact_detail.label :telephone %>
<%= contact_detail.number_field :telephone %>
</div>
<div class="field">
<%= contact_detail.label :mobile %>
<%= contact_detail.number_field :mobile %>
</div>
<% end %>
</div>
...
But my contact detail fields are not shown. Any ideas?
You have to "seed" the relation in order for the inputs for an association to appear. fields_for works like a loop. If the association is empty or nil the block runs 0 times.
Normally you would do this in the new action of your controller:
class UsersController < ApplicationController
def new
#user = User.new
#user.build_contact_detail
end
end
In Devise the new action is Devise::RegistrationsController#new which you can customize by subclassing the controller:
class MyRegistrationsController < Devise::RegistrationsController
def new
super do |user|
user.build_contact_detail
end
end
end
super do |user| ... end uses the fact that all the Devise controller actions take a block and yield the resource. This makes it really easy to customize them without copy-pasting the entire method.
You then have to alter the routes so that your custom controller is used:
Rails.application.routes.draw do
devise_for :users, controllers: {
registrations: 'my_registrations'
}
end

How to debug why an update won't work with Rails associations?

I'm trying to setup a simple rails app with job board functionality. I was able to add jobs to the database, until I added an association between my Job model and devise User model. Now it won't update the database when I fill out the form.
jobs_controller
class JobsController < ApplicationController
def index
#jobs = Job.all
end
def new
#job = Job.new
end
def listing
end
def listings
end
def create
#job = Job.new(params.require(:job).permit(:title, :description, :url, :user_id))
if #job.save
redirect_to root_path
else
render "new"
end
end
end
new.html.erb
<%= simple_form_for #job do |form| %>
<%= form.input :title, label: "Job title" %>
<%= form.input :description, label: "Description" %>
<%= form.input :url, label: "URL" %>
<%= form.button :submit %>
<% end %>
index.html.erb
<% #jobs.each do |job| %>
<div class="job">
<h2><%= link_to job.title, job.url %></h2>
<p><%= job.description %></p>
</div>
<% end %>
<p><%= link_to "Add a job", new_job_path %></p>
user.rb
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :jobs
end
job.rb
class Job < ApplicationRecord
belongs_to :user
end
There isn't an error in the console, but the database doesn't seem to be updated or it's not updating the view.
I also ran a migration:
class AddUserToJob < ActiveRecord::Migration[5.2]
def change
add_reference :jobs, :user, foreign_key: true
end
end
You can get the user with current_user in Devise.
class JobsController < ApplicationController
# This restricts the actions to authenticated users and prevents a nil error
before_action :authenticate_user, except: [:show, :index]
# ...
def create
# this sets the user_id column
#job = current_user.jobs.new(job_params)
if #job.save
# you really should set a flash message or something to notify the user
# and possibly redirect to the show or index action instead
redirect_to root_path
else
render "new"
end
end
private
def job_params
params.require(:job)
.permit(:title, :description, :url, :user_id)
end
end
If you don't want to associate the job immediately to a user, you need to change the association to be optional, like:
class Job < ApplicationRecord
belongs_to :user, optional: true
end
Else you need to supply user_id in your form or set it in the controller action.
You should also delegate this part to a separate method
def job_params
params.require(:job).permit(:title, :description, :url, :user_id)
end
Job.new(job_params)

Profile Model with Devise Users in Rails

I'm trying to create a separate Profile model for Devise Users with things such as location, biography, blah, blah, blah. The problem is that I can't get it to save to the database.
My users are called "artists".
### /routes.rb ###
get 'artists/:id/new_profile' => 'artists/profiles#new', as: :profile
post 'artists/:id/new_profile' => 'artists/profiles#create'
### artists/profiles_controller.rb ###
class Artists::ProfilesController < ApplicationController
before_action :authenticate_artist!
def new
#artist = current_artist
#profile = ArtistProfile.new
end
def create
#artist = current_artist
#profile = ArtistProfile.new(profile_params)
if #profile.save
redirect_to current_artist
else
render 'new'
end
end
end
### /artist.rb ###
class Artist < ActiveRecord::Base
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable, :lockable, :timeoutable
has_one :artist_profile, dependent: :destroy
### /artist_profile.rb ###
class ArtistProfile < ActiveRecord::Base
belongs_to :artist
validates :artist_id, presence: true
end
### /views/artists/profiles/new.html.erb ###
<%= form_for(#profile, url: profile_path) do |f| %>
<div class="field">
<%= f.label :biography, "biography", class: "label" %>
<%= f.text_area :biography, autofocus: true , class: "text-field" %>
</div>
<div class="field">
<%= f.label :location, "location", class: "label" %>
<%= f.text_field :location, class: "text-field" %>
</div>
...
...
...
<div class="actions">
<%= f.submit "create profile", class: "submit-button" %>
</div>
<% end %>
What am I doing wrong here?
You need to initialise the profile using the current_artist object.
class Artists::ProfilesController < ApplicationController
before_action :authenticate_artist!
def new
#artist = current_artist
#profile = #artist.build_profile
end
def create
#artist = current_artist
#profile = #artist.build_profile(profile_params)
if #profile.save
redirect_to current_artist
else
render 'new'
end
end
end
Update:
To use this example your association should be like
class Artist < ActiveRecord::Base
has_one :profile, class_name: ArtistProfile
end
Make sure you set the artist_id for the profile before attempting to save.
#profile = ArtistProfile.new(profile_params, artist_id: #artist.id)
or
#profile = ArtistProfile.new(profile_params)
#profile.artist_id = #artist.id
should work.
In your controller you are missing the profile_params method.
private
def profile_params
params.require(:profile).permit(:biography, :location)
end

Understanding MVC for Rails 4 with image upload form

I am learning rails and I am trying to understand how the MVC model works with rails 4. I am practicing this by creating a form that will allow the user to upload an image with a name to the database. I am using CarrierWave to handle image storage in the database. This is what I have so far. As I am new to Rails 4, I'm not sure how all these parts connect together.
Here are my models for User and IncomePicture:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:rememberable, :validatable
has_many :expense_pictures
has_many :income_pictures
end
class IncomePicture < ActiveRecord::Base
belongs_to :user
mount_uploader :image, ImageUploader
has_one :income_text
end
Controllers:
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 create
# create IncomePicture object with params
#income_picture = IncomePicture.new(IncomePicture_params)
#
if #income_picture.save
flash[:notice] = "Income picture successfully uploaded"
redirect_to
end
private
def IncomePicture_params
params.require(:income_picture).permit(:image, :name)
end
end
view for form:
<%= form_for #income_picture, :html => { :multipart => true } do |f| %>
<p>
<%= f.label :name %>
<%= f.text_field :name %>
</p>
<p>
<%= f.file_field :image %>
</p>
<p><%= f.submit %></p>
<% end %>
I'm not sure how to create a form that will store the upload to the logged in user. Currently only the user login portion works.
I am getting this error when I try to run rails s
First argument in form cannot contain nil or be empty
on the line
--> <%= form_for #income_picture, :html => { :multipart => true } do |f| %>
<p>
<%= f.label :name %>
<%= f.text_field :name %>
As the error says, the first argument of form_for cannot be nil or empty which means that #income_picture, the first argument, is most probably nil. So you have to ask why this variable is nil and where should I define it.
I'm assuming that the form is under app/views/income_pictures/new.html.erb which means that the most probable action corresponding to that view is the new action under IncomePicturesController.
Add a new action in the IncomePicturesController and define #income_picture
class IncomePicturesController < ApplicationController
def new
#income_picture = IncomePicture.new
end
...
end

Error with nested attributes for a users model with devise on Rails 4?

I'm trying to create a new record for a model that belongs to my main model on the main model's update page, but it is not being saved to the database. Basically the Company model acts as the main user model, and it has the ability to create new board members for itself on its edit registration page that devise generates. Here is what I have.
1) my company model which has many boardmembers
class Company < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :boardmembers
accepts_nested_attributes_for :boardmembers
end
2) my boardmembers model
class Boardmember < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
belongs_to :company
end
3) the companies controller
class Companies::RegistrationsController < Devise::RegistrationsController
prepend_before_filter :require_no_authentication, only: [ :new, :create, :cancel ]
prepend_before_filter :authenticate_scope!, only: [:edit, :update, :destroy]
def create
build_resource(sign_up_params)
if resource.save
redirect_to edit_company_registration_path
else
clean_up_passwords resource
respond_with resource
end
end
def update
# For Rails 4
account_update_params = devise_parameter_sanitizer.sanitize(:account_update)
# For Rails 3
# account_update_params = params[:user]
# required for settings form to submit when password is left blank
if account_update_params[:password].blank?
account_update_params.delete("password")
account_update_params.delete("password_confirmation")
end
#company = Company.find(current_company.id)
# saves the companies boardmembers
if #company.update_attributes(account_update_params)
set_flash_message :notice, :updated
# Sign in the user bypassing validation in case his password changed
sign_in #company, :bypass => true
redirect_to company_home_path
else
render 'edit'
end
end
end
3) and my application controller where i configure params
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
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:account_update) do |u|
u.permit(:email, :name, :address, :jurisdiction_of_incorporation, :entity_type, :password, :password_confirmation, boardmembers_attributes: [:company_id, :id, :email, :name, :address, :secondary_email, :primary_phone, :password])
end
devise_parameter_sanitizer.for(:sign_up) do |u|
u.permit(:email, :name, :password, :password_confirmation)
end
end
end
My forms look something like this: edit.html.erb
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
<!-- here is where all the company update fields go -->
...
<!-- here are the fields for creating boardmembers
<%= f.fields_for :boardmembers, resource.boardmembers.build do |boardmember| %>
<%= boardmember.text_field :name %>
<%= boardmember.text_field :address %>
<%= boardmember.text_field :primary_phone %>
<%= boardmember.text_field :email %>
<%= boardmember.text_field :secondary_email %>
<%= boardmember.password_field :password %>
<% end %>
<%= f.submit "Update Your Account" %>
<% end %>
However the company gets its records updated but the new boardmember is not created at all. I even tried rendering a json file of the params when i click the button and it ends up looking like
{"utf8":"✓","_method":"put","authenticity_token":"mK4yd8t4m7N5rdfmHG8XKc/c+vNUdO8vryk5kYm7juw=","company": {"email":"pizzahut#email.com","name":"Pizza Comp","password":"","password_confirmation":"","entity_type":"","jurisdiction_of_incorporation":"","address":"","boardmembers_attributes":{"0":{"name":"","address":"","primary_phone":"","email":"","secondary_email":"","password":""}}},"commit":"Update Your Account","action":"update","controller":"companies/registrations"}
All of the params for the boardmembers are empty even when I fill them in. I've tried every tutorial and answer online and none of them seem to work in this case. What else could it be? Any ideas? The new record is never created. Please help.
Try this
<%= form_for([resource,resource.with_boardmembers], as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
<!-- here is where all the company update fields go -->
...
<!-- here are the fields for creating boardmembers
<%= f.fields_for :boardmembers do |boardmember| %>
<%= boardmember.text_field :name %>
<%= boardmember.text_field :address %>
<%= boardmember.text_field :primary_phone %>
<%= boardmember.text_field :email %>
<%= boardmember.text_field :secondary_email %>
<%= boardmember.password_field :password %>
<% end %>
In your User model add
def with_boardmembers
self.boardmembers.build
self
end

Resources