Can't mass-assign protected attributes: email, password - ruby-on-rails

I know that you should use "attr_accessible" to allow mass-assign protection, and that's actually what I do in my user model. How come it still complains?
Can't mass-assign protected attributes: email, password
user controller:
class UsersController < ApplicationController
def index
#users = User.new
end
def show
#user = User.find(2)
end
def login
#user = Project.new(params[:user])
...
end
end
user model:
class User < ActiveRecord::Base
has_and_belongs_to_many :projects
belongs_to :project
belongs_to :ticket
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password
end
the view, _navigation.html.erb:
<%= form_for("user", :url => login_users_path, :html => { :method => :post }) do |f| %>
<%= f.label :email%>
<%= f.text_field(:email, :size => 30, :class => 'login_field', :placeholder => 'Användarnamn')%>
<%= f.label :password%>
<%= f.text_field(:password, :size => 30, :class => 'login_field', :placeholder => 'Lösenord')%>
<%= f.submit "Logga in", :class => 'login_submit btn btn-primary' %>
<% end %>
from config/routes.rb:
resources :users do
post :login, on: :collection, as: :login
end
Because I'm using the collection above it should (as far as I understand) be the correct control / model (user) that I'm using?

I think it should be User not Project
def login
#user = User.new(params[:user])
...
end

You should also change your index action to:
def index
#users = Users.all
end
And show action to:
def show
#user = User.find(params[:id])
end

Related

How to submit nested attributes via parent _form submit?

Upon clicking submit only the Duel attributes are passing - not Dueler.
duels_controller.rb
def new
#duel = Duel.new
#user = User.find(params[:challenge_daddy]) # This pulls in the ID for Challenged User
# Current User
#duel.duelers << Dueler.new(user_id: current_user.id, user_name: current_user.name, user_last_name: current_user.last_name)
#current_user_challenges = current_user.challenges.order(:created_at)
# Challenged User
#duel.duelers << Dueler.new(user_id: #user.id, user_name: #user.name, user_last_name: #user.last_name)
#challenged_user_challenges = #user.challenges.order(:created_at)
respond_with(#duel)
end
I think I have to submerge the dueler info (i.e. full_name and collection_select) within something like <%= simple_form_for(#dueler) do |f| %>, but then I don't want two separate submit buttons. When the user clicks submit the dueler and duel information should both submit since they go hand-in-hand. Right now only the duel information submits and the duelers are never created.
duels/_form.html.erb
<%= simple_form_for(#duel) do |f| %>
<%= current_user.full_name %> WILL <%= collection_select(:dueler, :challenge_id, #current_user_challenges, :id, :full_challenge, include_blank: true) %>
<%= #user.full_name %> WILL <%= collection_select(:dueler, :challenge_id, #challenged_user_challenges, :id, :full_challenge, include_blank: true) %>
THE LOSER WILL <%= f.text_field :consequence %>.
<%= f.submit %>
<% end %>
UPDATE
Originally I had this in the _form:
<%= f.fields_for :duelers do |dueler| %>
<%= render 'dueler_fields', :f => dueler %>
<% end %>
But I took it out because the duels_controller new logic wasn't passing into it so I moved the code directly into the _form, but now I'm not sure what should take the place of <%= f.fields_for :duelers do |dueler| %>
class Dueler < ActiveRecord::Base
belongs_to :user
belongs_to :challenge
belongs_to :duel
end
class Duel < ActiveRecord::Base
belongs_to :user
belongs_to :challenge
has_many :duelers
accepts_nested_attributes_for :duelers, :reject_if => :all_blank, :allow_destroy => true #correct
end
class DuelsController < ApplicationController
before_action :set_duel, only: [:show, :edit, :update, :destroy, :duel_request]
respond_to :html
def index
#duels = Duel.joins(:duelers).all
redirect_to duel(#duel)
end
def duel_request
#dueler = #duel.duelers.where(user_id: current_user)
end
def show
#dueler = Dueler.find_by(user_id: current_user.id)
respond_with(#duel)
end
def user_challenges
#user = User.find_by_name(params[:name])
#challenges = #user.challenges.order(:created_at)
end
def new
#duel = Duel.new
#user = User.find(params[:challenge_daddy])
#duel.duelers << Dueler.new(user_id: current_user.id, user_name: current_user.name, user_last_name: current_user.last_name)
#current_user_challenges = current_user.challenges.order(:created_at)
#duel.duelers << Dueler.new(user_id: #user.id, user_name: #user.name, user_last_name: #user.last_name)
#challenged_user_challenges = #user.challenges.order(:created_at)
respond_with(#duel)
end
def edit
end
def create
#duel = Duel.new(duel_params)
#duel.save
#redirect_to duel_request_url(#duel)
respond_with(#duel)
end
def update
#duel.update(duel_params[:duelers_attributes])
respond_with(#duel)
end
def destroy
#duel.destroy
respond_with(#duel)
end
private
def set_duel
#duel = Duel.find(params[:id])
end
def duel_params
params.require(:duel).permit(:consequence, :reward, duelers_attributes: [:id, :user_id, :challenge_id, :accept])
end
end
If you are using has_many and belongs_to with accepts_nested_attributes you will need to use inverse_of to prevent Rails from attempting to lookup records (which of course don't exist because you haven't yet created them)
Change your Duel model has_many declaration to:
has_many :duelers, inverse_of: :duel
For further details on this and an example of a nested form with has_many relationship using Simple Forms check out:
https://robots.thoughtbot.com/accepts-nested-attributes-for-with-has-many-through

Adding a Spec (profile) to a current user

Hello Stackoverflow programmer's,
I'm currently running a small side-project next to my school's project but i'm quite stuck for a while now.
Here's my problem: I have a user with some standerd attributes and that user has_one :spec. A spec is sort of an extended version for a profile.
Now this spec has as i mentioned some extra attributes, but i can't seem to assign it correctly to the current user. The strange thing is i am able to make a spec in the console.
Here's my Spec_controller:
class SpecController < ApplicationController
def index
# redirect_to :controller => "user", :action => "index"
# #user.spec = #spec.new
end
def update
#user = User.find(current_user.id)
#spec.user_id = current_user.id
#spec = current_user.spec(spec_params)
#spec = Spec.find(params[:id])
if #spec.update(params.require(:spec).permit(:first_name, :last_name, :gender, :birthdate, :occupation, :city, :state))
flash[:notice] = "Changes saved."
redirect_to users_path
else
flash[:notice] = "er ging iets mis!"
render 'edit'
end
end
def edit
#user = User.find(session[:user_id])
#spec = Spec.new
end
def new
#user = User.find(session[:user_id])
#spec = Spec.new
end
private
def spec_params
params.require(:spec).permit(:first_name, :last_name, :gender, :birthdate, :occupation, :city, :state)
end
def user_params
params.require(:user).permit(:screen_name, :email, :password)
end
end
The Spec model:
class Spec < ActiveRecord::Base
belongs_to :user
ALL_FIELDS = %w(first_name last_name occupation gender birthdate city state zip_code)
STRING_FIELDS = %w(first_name last_name occupation city state)
VALID_GENDERS = ["Male", "Female"]
START_YEAR = 1900
VALID_DATES = DateTime.new(START_YEAR)..DateTime.now
validates_inclusion_of :gender, in: VALID_GENDERS, allow_nill: false, message: "Must be male or female"
validates_inclusion_of :birthdate, in: VALID_DATES, allow_nill: false, message: "Is invalid"
end
The user model:
class User < ActiveRecord::Base
has_one :spec
validates_presence_of :email, :screen_name
validates_uniqueness_of :email, :screen_name
has_secure_password
extend FriendlyId
friendly_id :screen_name, use: :slugged
end
And the edit view in case if it's needed:
<%= form_for :spec do |form| %>
<fieldset>
<legend><%= #title %></legend>
<%= text_field_tag form, "first_name" %>
<%= text_field_tag form, "last_name" %>
<div class="form_row">
<label for="gender">Gender:</label><br>
<%= radio_button :spec, :gender, "Male" %> Male
<%= radio_button :spec, :gender, "Female" %> Female
</div>
<div class="form_row">
<label for="birthdate">Birthdate:</label><br>
<%= date_select :spec, :birthdate, :start_year => Spec::START_YEAR, :end_year => Time.now.year, :include_blank => true, :order => [:month, :day, :year] %>
</div>
<%= text_field_tag form, "occupation" %>
<%= text_field_tag form, "city" %>
<%= text_field_tag form, "state" %>
</br>
<%= submit_tag "Update", :class => "submit", :controller => :spec, :action => :update %>
</fieldset>
<% end %>
Routes file:
Rails.application.routes.draw do
resources 'spec'
#post ':controller(/:spec(/:id(.:edit)))'
get 'spec/index'
get 'spec/edit'
get 'profile/index'
get 'profile/show'
get 'profile/:screen_name', controller: 'profile', action: 'show'
resources :users, only: [:index, :new, :create, :login, :destroy, :edit, :show, :update]
controller :sessions do
get :login, to: 'sessions#new'
delete :logout, to: 'sessions#destroy'
post :authenticate, to: 'sessions#create'
end
root 'site#index'
get 'site/index'
get 'site/about'
get 'site/help'
end
I hope my code is readable, still trying to figure out alot of stuff inside of rails (first programming language).
Thanks!
Finnaly got it to work! Ive made a new def in Spec controller instead of update i made a create function. Kinda strange in the first place why i made it a update function when you want to create a complete new Spec!
Thanks alot for your help :) much appreciated.
try
#spec = current_user.spec
if #spec.update(spec_params)
...
Update:
I think the link to update spec will be something like this /specs/1/edit, getting and updating spec should be
#spec = Spec.find(params[:id])
if #spec.update(spec_params)
...

Undefined method error on User child object Rails 4

I have an object(Transaction) that belongs_to User and User has_many transactions. When I try and create this object in my rails form I get the following error:
undefined method `transaction_kind' for nil:NilClass
app/models/transaction.rb:10:in `create_transaction'
app/controllers/transactions_controller.rb:17:in `create'
The params hash being passed through my console after I submit the form looks like:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"XXXXX", "transaction"=>{"transaction_kind"=>"Deposit", "user_id"=>"113", "credit"=>"99"}, "commit"=>"Submit Request", "lender_id"=>"113"}
Transaction.rb looks like this:
class Transaction < ActiveRecord::Base
belongs_to :user
after_save :create_transaction
attr_accessible :transaction_kind, :user_id, :credit, :debit, :created_at
def create_transaction
client = Restforce.new
credit = '012c00000004k5A'
debit = '012c00000004k55'
if #transaction.transaction_kind == "Deposit"
client.create!('Transaction__c', Account__c: self.salesforce_id, RecordTypeId: credit, Debit_Amount__c: self.debit, Credit_Amount__c: self.credit, Recorded_On__c: self.created_at, Status__c: 'New Transaction', Type: 'Deposit', Transaction_Type__c: self.transaction_kind)
else
client.create!('Transaction__c', Account__c: self.salesforce_id, RecordTypeId: debit, Debit_Amount__c: self.debit, Credit_Amount__c: self.credit, Recorded_On__c: self.created_at, Status__c: 'New Transaction', Type: 'Withdrawal', Transaction_Type__c: self.transaction_kind)
end
end
end
new.html.erb has the following form code:
<%= form_for [#user, #transaction], url: lender_transaction_path(#user) do |f| %>
<%= f.hidden_field :transaction_kind, :value => "Deposit" %>
<%= f.hidden_field :user_id, :value => #user.id %>
<%= f.label :credit, :class => "required" %>
<%= f.text_field :credit, :autofocus => :true, :class => "form-control margin-bottom-20 required"%>
<%= f.submit 'Submit Request', :class => "btn-u btn-u-primary" %>
<% end %>
transactions_controller.rb
class TransactionsController < ApplicationController
before_filter :authenticate_user!
def new
#user = current_user
#transaction = Transaction.new
if #user.activated?
client = Restforce.new
#account = client.find('Account', #user.salesforce_id, 'Account_Id')
transaction_query = "select from where Account__c ='%s' AND " % #account.Id.to_s
#transactions = client.query(transaction_query)
end
end
def create
#user = current_user
#transaction = Transaction.create(transaction_params)
if #transaction.save
redirect_to new_lender_transaction_path(#user)
end
end
private
def transaction_params
params.require(:transaction).permit(:transaction_kind, :credit, :debit, :created_at)
end
end
Any help with this issue would be great. Or any ideas on how to debug this further. Thanks!
You can't pass an instance variable from controller to model, so the Transaction model doesn't know what #transaction is and thus supposes it is as a nil
I would change the code into this:
if self.transaction_kind == "Deposit"
The self will make it work. If it is not, try using attr_accessor :transaction_kind or simply put if transaction_kind == "Deposit"
Also, I believe it would be better if you refactor the client.create! into:
Restforce.create!(...)
which will save you from writing another client = Restforce.new line.

Rails - Nested Form

I have Users who bet on matches. A single bet is called "Tipp" and the users predict the match score in "tipp.tipp1" and "tipp.tipp2"
I have problems with my form which is supposed to save "tipps" of users.
With the code below I get "Can't mass-assign protected attributes: tipp" although i have set "accepts_nested_attributes_for :tipps" and "attr_accessible :tipps_attributes".
I hope I have provided all the necessary code. Thanks in advance for your help!
Here is the parameters output:
Parameters:
{
"utf8"=>"✓",
"_method"=>"put",
"authenticity_token"=>"mPPpCHjA3f/M2l1Bd3ffO1QUr+kdETGkNE/0CNhbJXE=",
"user" =>{
"tipp"=>{
"6"=>{"tipp1"=>"4","tipp2"=>"6"},
"7"=>{"tipp1"=>"-1","tipp2"=>"-1"},
"8"=>{"tipp1"=>"-1","tipp2"=>"-1"}
}
},
"commit"=>"Update User",
"user_id"=>"1"
}
Shortened Code:
Controllers:
1) Users
class UsersController < ApplicationController
def edit_tipps
#user = current_user
end
def update_tipps
#user = current_user
if #user.update_attributes(params[:user])
flash[:notice] = "success (maybe)"
redirect_to user_edit_tipps_path(#user)
else
flash[:error] = "errors"
redirect_to user_edit_tipps_path(#user)
end
end
Models:
1) Users
class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation, :tipps_attributes
has_many :tipps
accepts_nested_attributes_for :tipps
end
2) Tipps
class Tipp < ActiveRecord::Base
attr_accessible :match_id, :points, :round_id, :tipp1, :tipp2, :user_id
belongs_to :user
end
My Form:
<%= form_for #user, :url => { :action => "update_tipps" } do |user_form| %>
<% #user.tipps.each do |tipp| %>
<%= user_form.fields_for tipp, :index => tipp.id do |tipp_form|%>
<%= tipp_form.text_field :tipp1 %><br/>
<%= tipp_form.text_field :tipp2 %><br/>
<% end %>
<% end %>
<%= submit_or_cancel(user_form) %>
<% end %>
Instead of doing what you did,
you could try either:
1.
Instead of:
<% #user.tipps.each do |tipp| %>
<%= user_form.fields_for tipp, :index => tipp.id do |tipp_form|%>
I would do this:
<%= user_form.fields_for :tipps do |tipp_form| %>
Or:
2.
class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation, :tipps_attributes, :tipps
Goodluck

Paperclip: "missing" image

I'm working on a website that allows people who run bed and breakfast businesses to post their accommodations.
I would like to require that they include a "profile image" of the accommodation when they post it, but I also want to give them the option to add more images later (this will be developed after).
I thought the best thing to do would be to use the Paperclip gem and have a Accommodation and a Photo in my application, the later belonging to the first as an association.
A new Photo record is created when they create an Accommodation. It has both id and accommodation_id attributes. However, the image is never uploaded and none of the Paperclip attributes get set (image_file_name: nil, image_content_type: nil, image_file_size: nil), so I get Paperclip's "missing" photo.
Any ideas on this one? It's been keeping me stuck for a few days now.
Accommodation
models/accommodation.rb
class Accommodation < ActiveRecord::Base
validates_presence_of :title, :description, :photo, :thing, :location
attr_accessible :title, :description, :thing, :borough, :location, :spaces, :price
has_one :photo
end
controllers/accommodation_controller.erb
class AccommodationsController < ApplicationController
before_filter :login_required, :only => {:new, :edit}
uses_tiny_mce ( :options => {
:theme => 'advanced',
:theme_advanced_toolbar_location => 'top',
:theme_advanced_toolbar_align => 'left',
:theme_advanced_buttons1 => 'bold,italic,underline,bullist,numlist,separator,undo,redo',
:theme_advanced_buttons2 => '',
:theme_advanced_buttons3 => ''
})
def index
#accommodations = Accommodation.all
end
def show
#accommodation = Accommodation.find(params[:id])
end
def new
#accommodation = Accommodation.new
end
def create
#accommodation = Accommodation.new(params[:accommodation])
#accommodation.photo = Photo.new(params[:photo])
#accommodation.user_id = current_user.id
if #accommodation.save
flash[:notice] = "Successfully created your accommodation."
render :action => 'show'
else
render :action => 'new'
end
end
def edit
#accommodation = Accommodation.find(params[:id])
end
def update
#accommodation = Accommodation.find(params[:id])
if #accommodation.update_attributes(params[:accommodation])
flash[:notice] = "Successfully updated accommodation."
render :action => 'show'
else
render :action => 'edit'
end
end
def destroy
#accommodation = Accommodation.find(params[:id])
#accommodation.destroy
flash[:notice] = "Successfully destroyed accommodation."
redirect_to :inkeep
end
end
views/accommodations/_form.html.erb
<%= form_for #accommodation, :html => {:multipart => true} do |f| %>
<%= f.error_messages %>
<p>
Title<br />
<%= f.text_field :title, :size => 60 %>
</p>
<p>
Description<br />
<%= f.text_area :description, :rows => 17, :cols => 75, :class => "mceEditor" %>
</p>
<p>
Photo<br />
<%= f.file_field :photo %>
</p>
[... snip ...]
<p><%= f.submit %></p>
<% end %>
Photo
The controller and views are still the same as when Rails generated them.
models/photo.erb
class Photo < ActiveRecord::Base
attr_accessible :image_file_name, :image_content_type, :image_file_size
belongs_to :accommodation
has_attached_file :image,
:styles => {
:thumb=> "100x100#",
:small => "150x150>" }
end
To create an upload with paperclip, you need to use the name you provided for the has_attached_file line, on the model you defined it on. In your case, this will result in this view code:
<%= form_for #accommodation, :html => { :multipart => true } do |f| %>
<%= f.fields_for :photo do |photo_fields| %>
<p>
Photo<br />
<%= photo_fields.file_field :image %>
</p>
<% end %>
<% end %>
In the controller:
class AccommodationsController < ApplicationController
# also protect create and update actions!
before_filter :login_required, :only => [ :new, :create, :edit, :update ]
def new
# always make objects through their owner
#accommodation = current_user.accommodations.build
#accommodation.build_photo
end
def create
#accommodation = current_user.accommodations.build(params[:accommodation])
if #accommodation.save
# always redirect after successful save/update
redirect_to #accommodation
else
render :new
end
end
end
Tell Rails to handle the nested form:
class Accommodation
has_one :photo
accepts_nested_attributes :photo
attr_accessible :photo_attributes, :title, :description, :etc
end
And make sure to set the accessible attributes right in your photo model:
class Photo
attr_accessible :image # individual attributes such as image_file_name shouldn't be accessible
has_attached_file :image, :styles => "etc"
end
Be sure to watch your log files to spot things that are protected by attr_accessible, but still are in your form.

Resources