samst
samst

Reputation: 556

rails parameters either blank or wrong

I tried everything but cannot make heads or tails of this ruby on rails in ´def new´ methode.

def edge_params
    params.require(:edge).permit(:kind, :start_id, :end_id, :property1)
end

This way the parameters end up at the ´Edge.save(edge_params)´ methode but ´:start_id´ and ´:end_id´ are foreign keys that both point to a Node.

def edge_params
  params.require(:edge).permit(:kind, :start_id, :end_id, :property1)
    p = { 
                :kind => params[:kind],
                :start_id => Node.where("nodeid = ?", params[:start_id]).first,
                :end_id => Node.where("nodeid = ?", params[:end_id]).first,
            :property1 => params[:property1]
        }
end

This executes but it always fails with complaining that all the required (validate presence of kind, start/end_id) are blank. I am doing something wrong here. I need to somehow find the Node ID because otherwise I get the expected Node but got String error. I am new to Ruby and it is quite a lot more difficult than it looks because it does so many things implicitly that one doesn't really know what one is doing. But it needs a ruby hash for the .save methode as much as i could figure out.

I also don't fully understand the require permit part. I got this from the tutorial on the rails page. Would params.require(:edge => [:kind,:start_id,:end_id]).permit(:property1) work too because that would make more logical sense for my data.

Additional Info

class Edge < ActiveRecord::Base
  belongs_to :start_id, :class_name => 'Node', :foreign_key => "start_id", :primary_key => "nodeid"
  belongs_to :end_id, :class_name => 'Node', :foreign_key => "end_id", :primary_key => "nodeid"
  validates :kind, presence: true
  validates :start_id, presence: true
  validates :end_id, presence: true
end

class Node < ActiveRecord::Base
    has_many :start_id, :class_name => 'Edge', :foreign_key => "start_id" , :primary_key => "nodeid"
    has_many :end_id, :class_name => 'Edge', :foreign_key => "end_id", :primary_key => "nodeid"
    validates :nodeid, presence: true, uniqueness: true, length: { minimum: 2 }
end

<%= form_for @edge do |f| %>
   <p>
      <%= f.label :kind %><br>
      <%= f.text_field :kind %>
    </p>
    <p>
      <%= f.label :start_id %><br>
      <%= f.text_field :start_id %>
    </p>
   <p>
      <%= f.label :end_id %><br>
      <%= f.text_field :end_id %>
    </p>
    <p>
      <%= f.label :propety1 %><br>
      <%= f.text_field :property1 %>
    </p>

Upvotes: 0

Views: 136

Answers (1)

engineersmnky
engineersmnky

Reputation: 29598

First your classes seem a bit off try this

class Edge < ActiveRecord::Base
  belongs_to :start_node, :class_name => 'Node', :foreign_key => "start_id", :primary_key =>"nodeid"
  belongs_to :end_node, :class_name => 'Node', :foreign_key => "end_id", :primary_key =>"nodeid"
  validates :kind, presence: true
  validates :start_id, presence: true
  validates :end_id, presence: true
end

class Node < ActiveRecord::Base
   has_many :start_edges, :class_name => 'Edge', :foreign_key => "start_id", :primary_key =>"nodeid"
   has_many :end_edges, :class_name => 'Edge', :foreign_key => "end_id", :primary_key =>"nodeid"
   validates :nodeid, presence: true, uniqueness: true, length: { minimum: 2 }
end

why are you building a Hash after the require? This should work fine.

def create
   @edge = Edge.new(edge_params)
   if @edge.save
     redirect_to edge_path(@edge)
   else
     render 'new'
   end
end
private
   def edge_params
     params.require(:edge).permit(:kind,:start_id,:end_id,:property1)
   end

There is not need to submit the nodes as actual Node objects. This association is made in the model through ORM (Object Relational Mapping). When you call @edge.start_node it will execute a query that looks like

"SELECT nodes.* FROM nodes where nodes.nodeid = THIS EDGES START_ID" 

Also I am sure there is some reason that you are using nodeid in place of the standard id column but I wouldn't recommend it. I would make the associations like this instead.

class Edge < ActiveRecord::Base
  belongs_to :start_node, :class_name => 'Node', :foreign_key => "start_id"
  belongs_to :end_node, :class_name => 'Node', :foreign_key => "end_id"
  validates :kind, presence: true
  validates :start_id, presence: true
  validates :end_id, presence: true
end

class Node < ActiveRecord::Base
   has_many :start_edges, :class_name => 'Edge', :foreign_key => "start_id"
   has_many :end_edges, :class_name => 'Edge', :foreign_key => "end_id"
   validates :nodeid, presence: true, uniqueness: true, length: { minimum: 2 }
end

Then Edge and Node will be associated through a incremented column called id that is built into Rails tables by default. The reason being is if you allow a user to change the nodeid on a Node it will break the realtionship chain to Edge where as using id the nodeid can change but it's relationships stay intact.

I would also recommend changing your form to use select boxes because you are not validating the existence of a Node at all right now but that seems like a separate issue.

To answer your question in the comments I would use a view like this.

<%= form_for @edge do |f| %>
  <p>
    <%= f.label :kind %><br>
    <%= f.text_field :kind %>
  </p>
  <p>
    <%= f.label :start_id %><br>
    <%= collection_select(:edge,:start_id,Node.all,:id,:nodeid) %>
  </p>
  <p>
    <%= f.label :end_id %><br>
    <%= collection_select(:edge,:end_id,Node.all,:id,:nodeid)  %>
  </p>
  <p>
    <%= f.label :propety1 %><br>
    <%= f.text_field :property1 %>
  </p>
  <%= f.submit %>
<% end %>

Upvotes: 1

Related Questions