Sinatra and Datamapper - inserting data to a one to many relationship table - ruby

I have the following. Each article has a title and a body and also up to three urls. I would want to store the urls in a different table. Therefore in my form, i've a field for the urls. However they are not working, only the article fields get entered into the database. how should i specify them? Could any kind soul help me out with this?
class Article
include DataMapper::Resource
property :id, Serial
property :title, String
property :body, Text
has n, :urls, through => Resource
end
class Url
include DataMapper::Resource
property :id, Serial
property :url_01, String
property :url_02, String
property :url_03, String
belongs_to :article
end
post '/create' do
#article = Article.new(params[:article])
if #article.save
redirect "/articles"
else
redirect "/articles/new"
end
end
--------------------------------------
<form action="/create" method="post">
<p>
<label>Article Title</label>
<input type="text" name="article[title]">
</p>
<p>
<label>Article Body</label>
<input type="text" name="article[body]">
</p>
<p>
<label>Url</label>
<input type="text" name="article[url_01]">
</p>
<p>
<input type="submit">
</p>

I believe that
, through => Resource
is only needed if you are doing a many-to-many relationship. A one-to-many, which I think is what you want, does not require that. Check out the post and comment relationship shown on the associations page.
EDIT for comment:
If I were you, I would name my form fields normally and construct the database object manually, for example:
<form action="/create" method="post">
<p>
<label>Article Title</label>
<input type="text" name="title">
</p>
<p>
<label>Article Body</label>
<input type="text" name="body">
</p>
<p>
<label>Url</label>
<input type="text" name="url">
</p>
<p>
<input type="submit">
</p>
and then:
post '/create' do
#article = Article.new(
:title => params[:title],
:body => params[:body]
)
#url = url.new(
url_01 => params[:url]
)
#article.url = #url
if #article.save
redirect "/articles"
else
redirect "/articles/new"
end
end

Related

Form Does not update database sinatra

I am facing issues with the connection of a form with the database, when I am trying to update a record using Sinatra.
I created a route and a form in a view.
At first the form connects to the get route and brings the relevant data. However, when I modify the fields and press the submit button to update the database, the record does not updated.
get'/users/:id/edit'do
# see the User we want to edit
#user = User.find_by_id(params[:id])
#Assign the values to all properties
#user.username = #user.username
#user.password = #user.password
#user.description =#user.description
#user.city = #user.city
#user.save
erb:edit
end
put 'users/:id/edit' do
#user = User.find_by_id(params[:id])
#Assign the values to all properties
#user.username = #user.username
#user.password = #user.password
#user.description =#user.description
#user.city = #user.city
#user.save
end
My form looks like this:
<form action="users/:id/edit" method="post" id="edit">
<input type="hidden" name="_method" value="put">
User ID : :<%=#user.id%> <br>
Username:<input type="text" name="username" value=
<%=#user.username%>"><br>
Password:<input type="password" name="password" value="
<%=#user.password%>"><br>
City:<input type="text" name="city" value="<%=#user.city%>">
<br>
Tell us more about you:<input type="text" name="description"
value="<%=#user.description%>"><br>
<input type="submit" name="Update" class="btn btn-primary " >
</form>
Can you please assist?
The form was passing the record id to the route, thus I modified the form to:
<form action="/users/edit/<%=#user.id%>" method="post"
id="edit">
and the route to:
put '/users/edit/:id' do
#user = User.find_by_id(params[:id])
#user.city= params[:city]
# rest of the fields need to be modified
end

Sinatra to-do list tutorial problems

So, I'm new to Ruby/Sinatra, did a bunch of codecademy lessons and the like. I decided until I actually built something, I wouldn't really understand some core concepts.
I found a tutorial for building a to-do list app in Sinatra, and all was fine and good until I got to the edit and delete functionality. I can read and write to/from the database, but whenever I try to edit or delete, it skips straight to "Note not found".
I couldn't figure this out myself, so I asked a developer friend of mine. When I sent him the code, everything worked absolutely fine for him! We tried a couple of different possible fixes, but to no end. I even downloaded the code from the guy's github, just in case there was a random mistake somewhere in my own code, to no avail.
So, I come here asking for some help! Why won't this work!
Clarification: Here's some of the code, where I think the problem may lie. In edit.erb and delete.erb, no matter what it is going to the else statement and sending me to "note not found". It's reading properly from the database, as my homepage can add and show notes.
recall.rb
get '/:id' do
#note = Note.get params[:id]
#title = "Edit note ##{params[:id]}"
erb :edit
end
put '/:id' do
n = Note.get params[:id]
n.content = params[:content]
n.complete = params[:complete] ? 1 : 0
n.updated_at = Time.now
n.save
redirect '/'
end
get '/:id/delete' do
#note = Note.get params[:id]
#title = "Confirm deletion of note ##{params[:id]}"
erb :delete
end
delete '/:id' do
n = Note.get params[:id]
n.destroy!
redirect '/'
end
edit.erb
<% if #note %>
<form action="/<%= #note.id %>" method="post" id="edit">
<input type="hidden" name="_method" value="put">
<textarea name="content"><%= #note.content %></textarea>
<input type="checkbox" name="complete" <%= "checked" if #note.complete %>>
<input type="submit">
</form>
<p>Delete</p>
<% else %>
<p>Note not found.</p>
<% end %>
delete.erb
<% if #note %>
<p>Are you sure you want to delete the following note: <em>"<%= #note.content %>"</em>?</p>
<form action="/<%= #note.id %>" method="post">
<input type="hidden" name="_method" value="delete">
<input type="submit" value="Yes, Delete It!">
Cancel
</form>
<% else %>
<p>Note not found.</p>
<% end %>
Moving the delete-route above the other routes seemed to work for me, which would suggest that the /:id -part in the route definition catches the /delete-part as well. You can see the generated regexps with Sinatra::Application.routes.
Here's a minimal:
require 'rubygems'
require 'sinatra'
require 'dm-core'
require 'dm-migrations'
require 'dm-sweatshop'
# Models
DataMapper.setup(:default, 'sqlite::memory:')
class Note
include DataMapper::Resource
property :id, Serial
property :content, Text, :required => true
property :complete, Boolean, :default => false
property :created_at, DateTime, :default => lambda {Time.now}
property :updated_at, DateTime
before(:save) { attribute_set(:updated_at, Time.now) }
end
DataMapper.finalize.auto_migrate!
# Fixtures
Note.fix {{
:content => /\w+/.gen
}}
100.of { Note.gen }
# Routes
before("/:id") {|id| #note = Note.get id }
get("/:id/delete") {|id| #note = Note.get id; erb :delete }
get("/:id") { erb :edit }
put "/:id" do
#note.attributes = params["note"]
#note.save ? redirect(to("/")) : erb(:edit)
end
delete("/:id") { #note.destroy; redirect(to("/")) }
# Templates
template :layout do
'<!DOCTYPE html>
<html>
<body><%= yield %></body>
</html>'
end
template :edit do
'<% if #note %>
<form action="/<%= #note.id %>" method="POST">
<input type="hidden" name="_method" value="PUT">
<textarea name="note[content]"><%= #note.content %></textarea>
<input type="checkbox" name="note[complete]"
<%= #note.complete? && "checked" %> >
<input type="submit">
</form>
<p>Delete</p>
<% else %>
<p>Note not found.</p>
<% end %>'
end
template :delete do
'<% if #note %>
<p>Are you sure you want to delete the following note:
<em>"<%= #note.content %>"</em>?</p>
<form action="/<%= #note.id %>" method="POST">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="Yes, Delete it!">
Cancel
</form>
<% else %>
<p>Note not found</p>
<% end %>'
end
I don't know if this is still interesting someone, but a simple
params[:id].to_i
fixed it for me.

Haml renders input element as escaped

I have a haml like ;
= form_for #company, :html => {:multipart => true}, :url => update_user_company_path do |f|
.field
Title:#{f.text_field :name}
= f.fields_for :attachments do |builder|
- if builder.object.new_record?
.field
= builder.hidden_field :name, :value => 'logo'
= builder.file_field :file
- elsif builder.object.name.eql?('logo') && !builder.object.file.url.eql?('/files/original/missing.png')
.field
%span.thumbnail
= link_to "Delete", delete_company_attachment_path(#company, builder.object), :method => :delete, :class => "remove_image"
= image_tag builder.object.file.url, :style => "height:86px;width:125px"
= f.submit 'Ok'
Chrome renders this code as intended, but in Firefox it is like;
<form method="post" id="edit_company_29" enctype="multipart/form-data" class="edit_company" action="/users/25/company" accept-charset="UTF-8"><div style="margin:0;padding:0;display:inline"><input type="hidden" value="✓" name="utf8"><input type="hidden" value="put" name="_method"><input type="hidden" value="thisismytokenvalue=" name="authenticity_token"></div>
<div class="field">
Title:<input type="text" value="sdgdfgghjh" size="30" name="company[name]" id="company_name">
</div>
<input id="company_attachments_attributes_0_id" name="company[attachments_attributes][0][id]" type="hidden" value="114" /><input id="company_attachments_attributes_1_id" name="company[attachments_attributes][1][id]" type="hidden" value="115" /><div class="field">
<input type="hidden" value="logo" name="company[attachments_attributes][2][name]" id="company_attachments_attributes_2_name">
<input type="file" name="company[attachments_attributes][2][file]" id="company_attachments_attributes_2_file">
</div>
<input type="submit" value="Ok" name="commit">
</form>
Why is an element escaped. If you check haml, you can see I didn't put them.
Where did it come from?
Why is it happening?
Wow ... I've just had a similar issue. My guess is that if you pass nil to the form_builder's fields_for the hidden_input isn't returned with html_safe. To quickly fix that add a
-else
=""
after the whole elsif block
You must return something other than nil in the fields_for block.
This issue has been fixed in Haml 4.0.4 by mattwildig, with the help of #lulalala. Here is an explanation of the problem:
The #fields_for helper generates a hidden input field for each record, which it adds to the result of capturing the block. Normally the return value of capture will be a SafeBuffer, so this won’t be escaped. However if the block doesn’t write anything to the buffer then Haml returns a literal empty String from capture. The hidden input element is concatted to this string, and when it is combined with the rest of the entries, since it is a String being added to a SafeBuffer, it gets escaped.

Sinatra/Carrierwave: how to update a record while using an existing image?

My super-simple Sinatra app is a list of notes, and each note has an attached image.
I've got a 'put' route set up that lets me update notes, but unless I re-upload the image, I lose it (note.image is set to 'nil' when I submit the form).
Thanks in advance for your help!
Here's my uploader:
class MyUploader < CarrierWave::Uploader::Base
include CarrierWave::MimeTypes
process :set_content_type
storage :fog
end
Here's my Note class:
class Note
include DataMapper::Resource
property :id, Serial
property :image, String, :auto_validation => false
property :content, Text, :required => true
property :created_at, Date
property :updated_at, Date
mount_uploader :image, MyUploader
end
Here's my 'put' route:
put '/:id' do
n = Note.get params[:id]
unless n
redirect '/', :error => "Can't find that note."
end
n.image = params[:image]
n.credit = params[:content]
n.date = params[:date]
n.updated_at = Time.now
if n.save
redirect '/', :notice => 'Note updated successfully.'
else
redirect '/', :error => 'Error updating note.'
end
end
And here's the form I'm using to update notes:
<% if #note %>
<form action="/<%= #note.id %>" method="post" id="edit" enctype="multipart/form-data">
<input type="hidden" name="_method" value="put">
<p><input type="text" name="credit" value="<%=h #note.content %>"></p>
<p><input type="file" name="image" /></p>
<br><br>
<input type="submit">
</form>
<% else %>
<p>Note not found.</p>
<% end %>
A simple if check is what you need: if params[image] is nil you skip the n.image = params[:image]
n.image = params[:image] if params[:image]
I use similar approach to create a custom Rails validation check when I work with ActiveRecord models that contain CarrierWave images. Probably it won't be a bad idea to check whether or not n.image isn't nil as well - if it's nil I guess it should be mandatory to upload an image.

Sinatra HTTP 'PUT' method

Something's wrong with the PUT action here, the form gets processed but the updated field is not being saved.
I've did what Sinatra users are doing, by adding in "_method" for Sinatra to recognise that's its a HTTP PUT action. Could anyone spot any mistake here?
# edit
get '/entries/*/:id/edit' do
#entry = Entries.get(params[:id])
#title = "edit"
erb :edit, :layout => :edit_layout
end
# update
put '/entries/:id' do
#entry = Entries.get(params[:id])
if #entry.save
redirect "/entries/id=#{#entry.id}"
else
redirect "/enewsletters"
end
end
<!-- Edit form -->
<form action="/enewsletters/edit/<%= #entry.id %>" method="post">
<input name="_method" value="put" type="hidden"/>
<p>
<label>Content</label><br/>
<input type="text" name="entry[title]" value="<%= #enew.title %>">
</p>
<p>
<input type="submit" name="commit" value="update">
</p>
</form>
You don't seem to be doing any update to the #entry, you're just fetching the specific entry with the id from params. Are you using ActiveRecord? If so, instead of #entry.save, try #entry.update_attributes(params[:entry]).
Edit: I'm guessing you're not using AR since I just noticed the .get call. Whatever ORM you are using must have an easy way to update the attributes and then save the record.

Resources