So I've been holding off putting a question on here because I don't want to bother the community with stupid questions, but I'm going to ask for help now anyway.
I'm quite new to Ruby on Rails, and as you've probably read from the title, I'm having trouble with my subform. More specifically, with assigning the parent object to a client object. I'm building a system for my work in where employees can register repairs (mobile phones) and keep track of them. I'm building the client object with #repair = Repair.new, which works fine, but when I try to set the Client with #repair = Client.new, the :client_id on the repair stays null.
Here's my repair.rb: (some fields are in Dutch, please ignore that)
class Repair < ActiveRecord::Base
attr_accessible :imei, :klantnaam, :telefoon, :intake, :branch_id, :id, :client_id
attr_accessible :merk, :type, :batterij, :lader, :headset, :batterijklep, :carkit, :schade_toestel, :schade_scherm, :bon, :datum_bon, :klacht, :prijsindicatie
belongs_to :branch
belongs_to :client
accepts_nested_attributes_for :client
end
client.rb:
class Client < ActiveRecord::Base
attr_accessible :email, :firstname, :lastname, :number, :phone, :postalcode
has_many :repairs
end
repairs_controller.rb: (I've left the irrelevant methods out, I was getting tired of the 4 spaces :P)
class RepairsController < ApplicationController
# GET /repairs/new
# GET /repairs/new.json
def new
#repair = Repair.new
#repair.client = Client.new
if request.remote_ip == "xx.xx.xx.xx"
#repair.branch = Branch.where(:name => "Xxxxxxx").first
end
#repair.intake = Time.now
respond_to do |format|
format.html # new.html.erb
format.json { render json: #repair }
end
end
# POST /repairs
# POST /repairs.json
def create
#repair = Repair.new(params[:repair])
respond_to do |format|
if #repair.save
format.html { redirect_to #repair, notice: 'Repair was successfully created.' }
format.json { render json: #repair, status: :created, location: #repair }
else
format.html { render action: "new" }
format.json { render json: #repair.errors, status: :unprocessable_entity }
end
end
end
end
And this is the JSON I get from /repair/new.json:
{"batterij":null,"batterijklep":null,"bon":null,"branch_id":null,"carkit":null,"client_id":null,"created_at":null,"datum_bon":null,"headset":null,"id":null,"imei":null,"intake":"2013-02-01T23:29:10Z","klacht":null,"klantnaam":null,"lader":null,"merk":null,"pickup":null,"prijsindicatie":null,"schade_scherm":null,"schade_toestel":null,"telefoon":null,"updated_at":null}
By the way, the branch assignment works flawlessly... (It's null now because I'm not on the IP I specified in the new method)
Please help me out... :-(
Robin
Solved it!!
The code above all works flawlessly, the problem was a <% instead of <%= in my view, which made my subform not show up. Duhh.
Related
Im new on Rails and I feel a kind of stuck right now, I need to develop an app where you associate Congresses and Users, has_and_belong_to_many, the point is that I have this on my view:
<div class="field">
<%= f.label :administrators_id %>
<%= f.collection_check_boxes :administrators_id, #users,'id','user_id',{multiple: true, class: 'checkbox inline'} %>
this is on my controllers:
def new
#congress = Congress.new
#users = User.all
end
# GET /congresses/1/edit
def edit
#users = User.all
end
# POST /congresses
# POST /congresses.json
def create
#congress = Congress.new(congress_params)
respond_to do |format|
if #congress.save
format.html { redirect_to #congress, notice: 'Congress was successfully created.' }
format.json { render :show, status: :created, location: #congress }
else
format.html { render :new }
format.json { render json: #congress.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /congresses/1
# PATCH/PUT /congresses/1.json
def update
respond_to do |format|
if #congress.update(congress_params)
format.html { redirect_to #congress, notice: 'Congress was successfully updated.' }
format.json { render :show, status: :ok, location: #congress }
else
format.html { render :edit }
format.json { render json: #congress.errors, status: :unprocessable_entity }
end
end
end
But I dont get it to work, checked vales adoes not store at all.
Thanks for your help!
class User < ApplicationRecord
has_many :adminstrations
has_many :congresses, through: :adminstrations
end
class Congress < ApplicationRecord
has_many :adminstrations
has_many :adminstrators, through: :adminstrations,
source: :user
end
class Administration < ApplicationRecord
belongs_to :user
belongs_to :congress
end
See Why You Don’t Need Has_and_belongs_to_many Relationships. You can call the join model whatever you want. But in 99% of cases you'll want to have it sooner or later.
To assign associations from an array (created by a select or checkboxes) you need to use the _ids setter. Not _id. _id is singular and will only work if the relation is one to one.
<div class="field">
<%= f.label :administrators_ids %>
<%= f.collection_check_boxes :administrators_ids, #users, :id, :email, {multiple: true, class: 'checkbox inline'} %>
</div>
The two methods should be the value and the label method to be used on the user instance when generating the option tags. Use symbols here instead of strings for readability.
Make sure you are whitelisting the correct param as well:
def congress_params
params.require(:congress)
.permit(:foo, :bar, :administrators_ids)
end
I'm posting here because i can't find anyone with this error. I'm using Rails 4.0.2 and when i try to save my form (it uses a collection_check_box) it gives me this message:
NoMethodError (undefined method `name' for nil:NilClass):
app/controllers/projeto_controller.rb:34:in `block in create'
app/controllers/projeto_controller.rb:33:in `create'
I'm a little lost here because i don't have any attributes named name.
Here my controllers and models.
class Projeto < ActiveRecord::Base
belongs_to :usuario
has_many :projeto_temas
has_many :temas, through: :projeto_temas
accepts_nested_attributes_for :temas
validates_presence_of :titulo, :orgao_financiador, :periodo_inicio, :periodo_fim
end
class ProjetoController < ApplicationController
# GET /projeto/new
def new
#projeto = Projeto.new
render :layout => 'application_cadastro'
end
# POST /projeto
# POST /projeto.json
def create
#projeto = Projeto.new(projeto_params)
respond_to do |format|
if #projeto.save
format.html { redirect_to #projeto, notice: 'Projeto was successfully created.' }
format.json { render action: 'show', status: :created, location: #projeto }
else
format.html { render action: 'new' }
format.json { render json: #projeto.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /projeto/1
# PATCH/PUT /projeto/1.json
def update
respond_to do |format|
if #projeto.update(projeto_params)
format.html { redirect_to #projeto, notice: 'Projeto was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #projeto.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_projeto
#projeto = Projeto.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def projeto_params
params.require(:projeto).permit(:titulo, :usuario_id, :orgao_financiador, :periodo_inicio, :periodo_fim, :resumo, :temas_ids => [])
end
end
And the Temas model.
class Temas < ActiveRecord::Base
has_many :relacionamento_temas_pai, class_name: RelacaoTemas, foreign_key: :temas_pai_id
belongs_to :relacionamento_temas_filho, class_name: RelacaoTemas, foreign_key: :temas_filho_id
has_and_belongs_to_many :projeto
accepts_nested_attributes_for :relacionamento_temas_pai
validates :nome, presence: true
end
The part of the view with the ckeck_box
<div class="presquisadores-preview-action">
<div class="temas-projetos-checkbox">
<%= f.collection_check_boxes :temas_ids, Temas.all, :id, :nome %>
</div>
</div>
It has one attribute with the name nome which is portuguese for name, so it shouldn't affect anything.
Thanks in advance for the help, in really lost, and don't know what to do.
--EDIT
So... after a lot of research i didn't find the problem. Actually i was looking into some rails documentation and saw some issues with that version of the activerecord so i updated to rails 4.2.0 and the problem is now gone.
I still don't know what caused it, but now my form saves normally.
Thanks for all the help folks
This is an issue with Rails 4.0.2. I faced the same issue and when I updated to Rails 4.0.13 (the last in the 4.0.x series), the issue resolved itself.
From the github issues, I can only glean that this is because of some database bugs that Rails did not prepare for.
I've tried to implement many of the proposed solutions in the relevant questions, but haven't yet found an answer ideal for what I'm trying to achieve in my Rails 4 application.
Basically my app has three models. Users, Hooks (embeddable pop-up widgets) and Contacts. Users can create Hooks and Contacts within their interface. And any visitor can create a new contact by filling out the Contact create form placed within a Hook's view, and that contact is associated with the user who created that hook.
That works fine, however when a contact is created by filling out a Hook's form, there's no connection to the specific Hook they completed the form in.
The next set of features I would like to add to my app requires not only associating each contact with a user, but also with the specific Hook it was created from.
I've read a bit into polymorphic associations (model belongs to multiple models) and I understand that's probably the way to go. After a couple of failed attempts, I'm not sure how to implement it though.
How would I associate Contacts with Hooks, so users can know which hook a contact was created from?
Here is what I currently have in the Hooks controller and model...
def create
#hook = hook.new(hook_params)
#hook.user = current_user
#contact = Contact.new(contact_params)
respond_to do |format|
if #hook.save
format.html { redirect_to #hook, notice: 'Hook was successfully created.' }
format.json { render :show, status: :created, location: #hook }
format.js
else
format.html { render :new }
format.json { render json: #hook.errors, status: :unprocessable_entity }
format.js
end
end
end
class Hook < ActiveRecord::Base
belongs_to :user
has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "https://s3.amazonaws.com/app/assets/leadmagnet.png"
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
end
And here is the contacts controller and model...
def create
#contact = Contact.new(contact_params)
#contact.user = current_user
respond_to do |format|
if #contact.save
if user_signed_in?
format.html { redirect_to #contact, notice: 'Contact was successfully created.' }
else
format.html { redirect_to #contact, notice: 'Contact was successfully created.' }
end
format.json { render :show, status: :created, location: #contact }
else
format.html { render :new }
format.json { render json: #contact.errors, status: :unprocessable_entity }
end
end
end
class Contact < ActiveRecord::Base
belongs_to :owner, :class_name => 'User'
belongs_to :user
validates :email, :presence => {:message => 'Email cannot be blank'}
end
First off, you should never ever ever create 2 unrelated models on the same controller action. It breaks conventions and will only lead to problems.
You do not need to directly associate Contacts to Users. You should associate Contacts to Hooks and then associate Contacts through Hooks
class User < ActiveRecord::Base
has_many :hooks
has_many :contacts, through: :hooks
end
class Hook < ActiveRecord::Base
belongs_to :user
has_many :contacts
accepts_nested_attributes_for :contacts
end
class Contact < ActiveRecord::Base
belongs_to :hook
end
Now on the create action of the ContactsController, you can first get the Hook either by URL param or passed via post body. You can first find the Hook and create the Contact on it via:
hook = Hook.find(hook_id)
#contact = hook.contacts.new(contacts_param)
If you want to create contacts when creating a new Hook, you need to add :contacts_attributes on the strong_params, then pass an array of contact attributes via the POST. Adding accepts_nested_attributes_for to the Hook model allows you to easily create Contacts while creating Hooks by simply entering:
#hook = Hook.new(hook_params)
If I understand correctly, you want to create both a Hook and a Contact, and associate both to current_user. In your code you create both, but you only associate #hook with the current_user, and only save it, while ignoring the #contact. Simply associate it and save it as well:
def create
#hook = hook.new(hook_params)
#hook.user = current_user
#contact = Contact.new(contact_params)
#contact.user = current_user
respond_to do |format|
if #hook.save && #contact.save
format.html { redirect_to #hook, notice: 'Hook was successfully created.' }
format.json { render :show, status: :created, location: #hook }
format.js
else
format.html { render :new }
format.json { render json: #hook.errors + #contact.errors, status: :unprocessable_entity }
format.js
end
end
end
I have several models (User, Goal) and my Goal model has several subtypes (Exercise, Yoga, etc.)
A user can have many goals, but only one of each type.
class User < ActiveRecord::Base
has_many :goals, dependent: :destroy
has_one :exercise
has_one :water
has_one :yoga
def set_default_role
self.role ||= :user
end
end
and
class Goal < ActiveRecord::Base
self.inheritance_column = :description
belongs_to :user
validates :user_id, presence: true
validates :description, presence: true
end
where a subclass of goal is just something like this
class Exercise < Goal
belongs_to :user
end
I want to create all types of goals in my goal controller and have it set up so that localhostL:3000/waters/new will be my "water goal-type" creation page. I'm having trouble correctly setting it up though so that description is automatically set (my STI column) because I also want to build it through my user (so user_id is also set).
my goals controller currently looks like this...
def create
#goal = current_user.goals.build
???? code to set goal.description = subtype that the request is coming from
respond_to do |format|
if #goal.save
format.html { redirect_to #goal, notice: 'Goal was successfully created.' }
format.json { render action: 'show', status: :created, location: #goal }
else
format.html { render action: 'new' }
format.json { render json: #goal.errors, status: :unprocessable_entity }
end
end
end
I'm pretty new to rails so a little bit confused. Also using Rails 4.0
In that case you'd need to communicate the type to create to the controller somehow.
This is most easily established by including a hidden field in the form which has a value of the type you want to create.
Assuming your block variable for the form is f
<%= f.hidden_field :type, :value => "Excercise" %>
Then you can build a goal like this:
current_user.goals.build(type: params[:type])
You can easily see how this can be very dangerous, you should always be doubly careful when using user submitted data.
To guard against a malicious user, you could set a constant in your controller
AcceptedModels = ["Excercise", "Yoga", "Water"]
def accepted_type
(AcceptedModels & params[:type]).first
end
If you also want to hide your internal structure, you could use a hash and send any identifier
AcceptedModels = {"0": "Excercise", "1": "Yoga", "2": "Water"}
def accepted_type
AcceptedModels.fetch(params[:type], nil)
end
in either case you can then build your goal like this:
current_user.goals.build(type: accepted_type)
The biggest downside with this is that you will have to keep the AcceptedModels updated whenever you add/remove more goals
i'v been researching trying to find the answer for this, but am struggeling to work it out. i have a booking_no text_field which i want to be automatically set when a user make a new booking through booking/new. i would like it to be an autonumber which just counts up by 1 evertime starting with 100.
I know it is probably easiest to do this in the model but i'm not sure how.
my booking.rb:
(i havent set the validates yet)
class Booking < ActiveRecord::Base
attr_accessible :booking_no, :car_id, :date, :user_id
belongs_to :car
belongs_to :user
end
EDIT for comment:
#error ArgumentsError in booking_controller#create
wrong number of arguments (1 for 0)
my booking_controller#create
def create
#booking = Booking.new(params[:booking])
respond_to do |format|
if #booking.save
format.html { redirect_to #booking, :notice => 'Booking was successfully created.' }
format.json { render :json => #booking, :status => :created, :location => #booking }
else
format.html { render :action => "new" }
format.json { render :json => #booking.errors, :status => :unprocessable_entity }
end
end
end
It's probably best if you set the booking_no as auto-increment field in the Database table itself..
Otherwise to manage it in your model, you can proceed something like:
before_create :increment_booking_no
def increment_booking_no
self.booking_no = (self.class.last.nil?) ? "0" : ((self.class.last.booking_no.to_i) + 1).to_s
end