I am trying to insert some default users in my project using seed.rb file. I have executed the following line in the console:
rake db:seed
and no errors were thrown, but the records were not created either. When I paste the code in the rails console, again no errors are shown. I am guessing that I am doing something wrong in the seed.rb file.
This is how my models are related:
security_user.rb
has_one :security_users_detail, dependent: :destroy
has_many :security_users_manage_securities
has_many :security_users_roles, through: :security_users_manage_securities
security_users_detail.rb
belongs_to :security_user
security_users_role.rb
has_many :security_users_manage_securities
has_many :security_users, through: :security_users_manage_securities
And this is the code that I have in my seed.rb file:
users = {
Admin: {
Information: {
email: 'test#gmail.com',
password: 'test',
password_confirmation: 'test'
},
Details: {
address: 'Not defined.',
city: 'Not defined.',
country: 'Not defined.',
egn: '0000000000',
faculty_number: '',
first_name: 'Admin',
gender: 'male',
gsm: '0000000000',
last_name: 'Not defined.',
skype: 'Not defined.'
},
Roles: %w(Administrator)
}
}
users.each do |user, data|
security_user = SecurityUser.new(data[:Information])
data[:Roles].each { |role|
security_user.security_users_manage_securities.build(security_users_role: SecurityUsersRole.find_by_role(role))
}
SecurityUser.where(email: security_user.email).first_or_create!(security_user.attributes)
security_users_detail = SecurityUsersDetail.new(data[:Details])
security_users_detail.security_user_id = security_user.id
SecurityUsersDetail.where(security_user_id: security_users_detail.security_user_id).first_or_create
end
seed.rb is a rake task, so you can use puts to output messages to the console. For instance,
puts "User name: #{user.name}"
The issue was caused by the following line:
security_user = SecurityUser.new(data[:Information])
because even thought the hash passed in the new method holds only email and password fields, the result object was created with the rest of the model attributes but set to nil. For, example, I have id=>nil.
Then in I was doing the following
SecurityUser.where(email: security_user.email).first_or_create!(security_user.attributes)
in order to created the user only if exists. Anyway, since the id parameter is not in the attr_accessible clause in the model, I was not able to make mass assign.
To delete the nil values of the hash I've done the following:
SecurityUser.where(email: security_user.email)
.first_or_create!(security_user.attributes
.delete_if { |key, value| value.nil? })
Related
Gone through a lot of answers but still couldn't find the solution.
I have been trying to get a successful response for a POST request to the following controller,
def create
#user = User.new(user_params)
if #user.save
render json: #user, status: :created, location: #user
else
render json: #user.errors, status: :unprocessable_entity
end
private
def user_params
params.require(:user).permit(:name, :email, :phone, :password)
end
end
Although I send all the parameters mentioned,in the request,I am still facing the error.
"status": 400,
"error": "Bad Request",
"exception": "#<ActionController::ParameterMissing: param is missing or the value is empty: user>"
I am using rails version 5.2.1
If you look at the logs, what does the data transferred in your post request look like?
When you get that type of error, often it's because you send the data like this:
{ first_name: 'John', last_name: 'Doe', ...}
When the server expects you to nest this into a user object (hence the require(:user) in your strong_params:
{ user: { first_name: 'John', ... } }
This is Worked for me.
I made just only one hash in params method instead of nested hash.
my user_params method was:-
def user_params
params.permit(:name, :email, :phone, :password)
end
OR You can you your method but your paramter passed in user hash like below.
{user: {name: "bittu", email: "abc#yopmail.com", phome: 123456, password: "123456" } }
we're trying to get our site to have less scrapeable AND more readable urls
so e.g.
www.loomio.org/discussions/3122
becomes
www.loomio.org/d/3saA4ds9/lets-go-to-the-moon
we only really want the human-readable slug on show-links, so www.loomio.org/d/3saA4ds9/edit should be the url for editing that discussion
the solution so far follows the top answer here:
Ruby on Rails: How to override the 'show' route of a resource?
modify routes.rb:
get '/d/:id/:slug', to: 'discussions#show', as: :discussion
resources :discussions, path: 'd', except: [:edit, :show] do
get :activity_counts, on: :collection
member do
post :update_description
post :add_comment
post :show_description_history
get :new_proposal
post :edit_title
put :move
end
end
install gem FriendlyID; make and populated a :key column on Discussion table; add the following to discussion.rb (model):
KEY_LENGTH = 10
extend FriendlyId
friendly_id :key
write a custom path helper for group_path. in groups_helper.rb:
def group_url(group, options={})
url_for(options.merge(:controller => 'groups', :action => 'show',
:id => group.key, :slug => group.full_name.parameterize))
end
def group_path(group, options={})
group_url(group, options.merge(:only_path => true))
end
rake routes produces:
group GET /g/:id/:slug(.:format) groups#show
and while calling group_path(group) seems to work in some cases, I'm also seeing strange unrelated urls get generated, like :
http://loomio.org/group_requests/TegFOIx4DB/start_new_group?action=show&controller=groups%2Fgroups&slug=19-tory
in console, I'm also getting errors such as:
[5] pry(main)> g = Group.last
[6] pry(main)> app.group_path(g)
ActionController::RoutingError: No route matches {:controller=>"groups", :action=>"show", :id=>#<Group id: 2811, name: "Sylvester Buckridge", created_at: "2013-12-10 06:25:42", updated_at: "2013-12-10 06:25:42", privacy: "public", members_invitable_by: "members", parent_id: nil, email_new_motion: true, hide_members: false, beta_features: false, description: "A description for this group", memberships_count: 1, archived_at: nil, max_size: 300, cannot_contribute: false, distribution_metric: nil, sectors: nil, other_sector: nil, discussions_count: 0, motions_count: 0, country_name: nil, setup_completed_at: "2013-12-10 05:25:01", next_steps_completed: false, full_name: "Sylvester Buckridge", payment_plan: "undetermined", viewable_by_parent_members: false, key: "rkdlTytOin">}
from /home/s01us/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.16/lib/action_dispatch/routing/route_set.rb:540:in `raise_routing_error'
I've tried putting the group_path and grop_url methods in ApplicationController and ApplicationHelper to no avail.
calling
group_path( group.key, group.fullname.parameterize )
works, but would ideally like to be able to only have to call e.g.
group_path(#group)
as far as i understand the problem, you could use the good old hack with defining the to_param method on your model
class Group < ActiveRecord::Base
def to_param
"#{id}-#{slug}"
end
end
The beauty of this solution is that you won't need to do anything else. Rails will automatically use the to_param method as your record ID when it generates an URL from a record. You can do anything
redirect_to group_path(#group)
redirect_to #grup
# etc
and your Group.find should eat it as it is 123-smth-smth, usually it is smart enough to extract the integer part of the id
I deeply searched the web in order to find a clean and simple way to deal with attributes initialization on the join model of a has_many :through relation, but I did not find a best solution for my need.
In the exaple I provide below, I need to automatically set the attribute role of the Training join model when I create or update a Course object.
This is my model:
QUALIFICATIONS = ["Theoretical Instructor", "Practical Instructor"]
class Course < ActiveRecord::Base
has_many :trainings, dependent: :destroy
has_many :theoretical_instructors, through: :trainings, source: :trainer, conditions: { "trainings.role" => "Theoretical Instructor" }
accepts_nested_attributes_for :theoretical_instructors
has_many :practical_instructors, through: :trainings, source: :trainer, conditions: { "trainings.role" => "Practical Instructor" }
accepts_nested_attributes_for :practical_instructors
end
class Trainer < ActiveRecord::Base
has_many :trainings, dependent: :destroy
has_many :courses, through: :trainings
end
class Training < ActiveRecord::Base
belongs_to :trainer
belongs_to :course
# Join model has the :role attribute, that I wish I could validate this way:
# validates :role, presence: true, inclusion: { in: QUALIFICATIONS }
end
The rationale behind this model is that I want to save Training objects in a single table. I don't want to create the TheoreticalInstructor and the PracticalInstructor join models (potentially exploding the number of tables) to solve this problem.
This view provides the form to submit a new Course:
<%= form_for #course do |course_form| %>
<%- # fields for course attributes, as usual... %>
<%= course_form.label :theoretical_instructor_ids %><br />
<%= course_form.select :theoretical_instructor_ids, Trainer.all.map { |x| [[x.name, x.surname].join(" "), x.id] }, { }, { multiple: true } %>
<%= course_form.label :practical_instructor_ids %><br />
<%= course_form.select :practical_instructor_ids, Trainer.all.map { |x| [[x.name, x.surname].join(" "), x.id] }, { }, { multiple: true } %>
<%= course_form.submit %>
<% end%>
The question is: what can I do in order to make #course = Course.new(params[:course]) the only line of code in the Course controller needed to save this association on submit of the previous form?
Differently from this question I don't want to create new Trainer objects when I create a new Course: I want to choose them from those already present in the DB (through a multiselect input field).
What I need is that something like #course.theoretical_instructor_ids = [1, 2] creates two Training objects with the role attribute set to Theoretical Instructor
I'm thinking on an after_initialize callback on Training that set role basing on the relation name (:theoretical_instructors and :practical_instructors), but I really don't know how to do it. Any advice? Am I missing some point?
Thank you guys!
EDIT 1 from oli-g
This question deals with a similar problem: the difference is that I don't want to build Trainer objects when I create a new Course, but I simply want to associate existing Trainer objects to a new Course.
EDIT 2 from oli-g
Basing on this (a 5 years old post) and this blog posts, I've changed the Course model in this way:
class Course < ActiveRecord::Base
has_many :trainings, dependent: :destroy
has_many :theoretical_instructors, through: :trainings, source: :trainer, conditions: ["trainings.role = ?", "Theoretical Instructor"] do
def <<(theoretical_instructor)
Training.send(:with_scope, create: { role: "Theoretical Instructor" }) { self.concat theoretical_instructor }
end
end
accepts_nested_attributes_for :theoretical_instructors
has_many :practical_instructors, through: :trainings, source: :trainer, conditions: ["trainings.role = ?", "Practical Instructor"] do
def <<(practical_instructor)
Training.send(:with_scope, create: { role: "Practical Instructor" }) { self.concat practical_instructor }
end
end
accepts_nested_attributes_for :practical_instructors
end
This code enables me to do a thing like this
:001 > c = Course.first
=> #<Course id: 1>
:002 > t1 = Trainer.first
=> #<Trainer id: 1, name: "Tom">
:003 > c.theoretical_instructors << t1
=> #<Trainer id: 1, name: "Tom">
:004 > Training.all
=> [#<Training id: 1, role: "Theoretical Instructor", trainer_id: 1, course_id: 1>]
This is an acceptable workaround, even if in my controller I still can't do just #course = Course.new(params[:course]), but I have to create Training objects iterating on params[:course][:theoretical_instructor_ids] and params[:course][:practical_instructor_ids].
But I am curious, so the question remains open: what can I do in order to enable #course = Course.new(params[:course]) to build Training objects along with the Course?
Now... I think I discovered a bug in Rails:
:005 > c.practical_instructors
=> [] # correct
:006 > c.practical_instructor_ids
=> [] # obviously
:007 > c.reload
=> #<Course id: 1>
:008 > c.practical_instructor_ids
=> [1] # WRONG!!!
:009 > c.practical_instructors
=> [] # now it's correct...
:010 > c.practical_instructor_ids
=> [] # WTF!?
I think I will report this at github issues...
EDIT 3 by oli-g
Bug reported at github
Your issue is that you won't be able to add associations until after your record has been created. In this case, the Training associations are stored using the Course record id, and the Course id isn't defined until after the Course is saved for the first time. What you'll want to do is to use the after_create callback to call a function after the record has been created.
Add this to the end of your Course model:
# Use attr accessors to store the initial values so they won't conflict with the *_instructor_ids methods defined above
attr_accessor :create_theoretical_instructors
attr_accessor :create_practical_instructors
# This will call the create_training_records function after the record is created
after_create :create_training_records
private
def create_training_records
create_theoretical_instructors.each do |instructor_id|
self.theoretical_instructors << Instructor.find(instructor_id)
end
create_practical_instructors.each do |instructor_id|
self.practical_instructors << Instructor.find(instructor_id)
end
save!
end
And change the form in your view to use the new attr_accessors:
<%= course_form.label :create_theoretical_instructors %><br />
<%= course_form.select :create_theoretical_instructors, Trainer.all.map { |x| [[x.name, x.surname].join(" "), x.id] }, { }, { multiple: true } %>
<%= course_form.label :create_practical_instructors %><br />
<%= course_form.select :create_practical_instructors, Trainer.all.map { |x| [[x.name, x.surname].join(" "), x.id] }, { }, { multiple: true } %>
Now when you submit the form, it will write the instructor ids to the new Course instance variables; after the Course has been validated and saved, it will automatically create the new associations.
I'm having a problem with associations not being available in my views.
My models are:
:user has_many :subscriptions
:subscription belongs_to :user
I'm using Devise to manage authentication etc. for Users
What I'd like to do: when creating a new user in the registration process, I also want to also create a subscription for that user.
Since Devise::RegistrationsController#new by default does not initialize an associated subscription, I've created my own RegistrationsController:
class RegistrationsController < Devise::RegistrationsController
def new
super
resource.subscriptions.build
logger.debug resource.subscriptions.inspect
end
end
The debug statement there confirms that a Subscription object is successfully created:
[#<Subscription id: nil, user_id: nil, chargify_subscription_id: nil, chargify_product_handle: nil, created_at: nil, updated_at: nil>]
The problem: in the view, resource.subscriptions does not exist.
If I inspect resource in the view, I get a User object that includes all of its own attributes but no associations (it should have an associated subscriptions)
debug(resource) gives the following:
--- !ruby/object:User
attributes:
name:
encrypted_password: ""
created_at:
updated_at:
last_sign_in_ip:
last_sign_in_at:
sign_in_count: 0 last_name:
current_sign_in_ip:
reset_password_token:
current_sign_in_at:
remember_created_at:
reset_password_sent_at:
chargify_customer_reference:
first_name:
email: ""
attributes_cache: {}
changed_attributes: {}
destroyed: false
marked_for_destruction: false
new_record: true
previously_changed: {}
readonly: false
Is there something I'm missing, or perhaps is there something strange about the resource mechanism used by Devise that prevents associations from being available in the view?
Thanks!
Edit:
If I just add resource.subscriptions.build in my view before rending the form, that works fine. But I think that kind of logic belongs in the controller and not the view, and I'd like to know what's keeping me from being able to put it there.
This answer is really late, but I found that if I override the entire controller action "new" (instead of delegating some of it to the parent with "super"), then I can build the resource properly. The reason is because "super" renders the view before handing control back to your custom controller method. Long story short...
class RegistrationsController < Devise::RegistrationsController
def new
resource = build_resource({}) # as found in Devise::RegistrationsController
resource.subscriptions.build
respond_with_navigational(resource){ render_with_scope :new } # also from Devise
end
end
Should work nicely...at least it did for me. Your code got me started on the right track anyway.
I have a Client and ProposalRequest model that look like this:
class Client < ActiveRecord::Base
has_many :proposal_requests
accepts_nested_attributes_for :proposal_requests, :allow_destroy => true
end
class ProposalRequest < ActiveRecord::Base
belongs_to :client
end
In my my routes file, I included the nested routes, as usual.
resources :clients do
resources :proposal_requests
end
And this is my form so far:
-semantic_form_for [Client.new, ProposalRequest.new] do |f|
=f.inputs
=f.buttons
But after this, I'm stuck because of this error.
No route matches {:controller=>"proposal_requests", :client_id=>#<Client id: nil, name: nil, title: nil, organization: nil, street_address: nil, city: nil, state: nil, zip: nil, phone: nil, email: nil, status: "interested", how_you_heard: nil, created_at: nil, updated_at: nil>}
Can anyone help me puzzle out this error?
The problem is that your nested route is meant to add a new ProposalRequest to an existing Client. If you want to create a Client and a ProposalRequest at the same time, you need to just use new_client_path and semantic_form_for #client do |f|.
I would recommend you do the following in your clients_controller:
def new
#client = Client.find(params[:id])
#client.proposal_requests.build
end
And in your view:
semantic_form_for #client do |f|
= f.inputs # fields for client
= f.inputs :name => 'Proposal Request', :for => :proposal_requests do |pf|
= pf.input :some_proposal_request_attribute
= f.buttons
Hope this helps. Make sure to look at all the examples at https://github.com/justinfrench/formtastic and do some trial and error to get your form how you want it.