I currently have a very simple model "Coupon". I suddenly am interested to add two more fields, "redeem_code" and "redeemed" to the model for obvious reasons.
I would like to make a view for a merchant to redeem a coupon based on a code.
The simplest approach that I can think of to just do this would be something like this:
def redeem
#renders the page
end
def redeem_post
redeem_code = params[:redeem_code]
deal = Deal.find_by_redeem_code(redeem_code)
if deal.nil?
# BUG: Somehow here you will be logged out
redirect_to deals_path
else
if deal.update_attribute(:redeemed, true)
redirect_to deals_path
end
end
end
As far as I am concerned, rails doesn't really support non restful interfaces. I tried digging up form helpers last night but I was not able to find anything so I just put togehter something real fast:
<form action="<%= deals_redeem_post_path %>" method="post">
<table>
<tr>
<th> Code: </th>
<td> <input type="text" name="redeem_code" /> </td>
</tr>
<tr>
<th></th>
<td> <input type="submit" text="Submit" /> </td>
</tr>
</table>
</form>
I am using devise. The bug that I am experiencing right now is when my user submits this form, he/she will be automatically logged out.
Any ideas how I can fix this or implement this more elegantly?
My guess is that you are missing the authenticity token (which prevents Cross Site Request Forgery (CSRF)) which is automatically generated. You want to use the form for helper for that generates this automatically.
<%= form_for(:coupon, :url => deals_redeem_post_path) do |f| %>
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_for
Related
I'm working on an application that makes some calls to the Twitter and Spotify APIs. After the user is authenticated with twitter, they are redirected to playlist.erb which is the callback url.
My problem is that the playlist.erb page takes a while to render because first we must make a call to fetch all tweets found on the users Twitter page, then try to find information about songs/artists, then use the Spotify API to search for a song that is closest to what information the user specified. Doing this for each tweet takes quite a while. For 10 tweets it sometimes takes between 5-10 seconds. The limit is 50 tweets in total.
The current playlist.erb page after it is fully loaded looks like this.
My question is, is there a way that I can render the page first, then get the partials for each individial tweet to render one at a time,
adding a new row for each tweet as it loads?
I've read that I should use something called AJAX, but I'm not sure how exactly to implement that here.
Also I'm aware that my view could use fixing in terms of CSS refactoring and not using the deprecated <center></center> HTML tags. And I should probably do a whole refactor of the system using proper MVC.
In the playlist.erb, a call to the Twitter API is made through the TweetsController to find all tweets from a page. the _tweet.erb partial is then rendered to this view for each tweet when new_tweet(tweet.text) is called. This method makes a call to the Spotify API to find details about the song mentioned in the tweet.
new_tweet is a method in a helper called playlist_helper.rb.
load_tweets is a method in a controller called tweets_controller.rb.
I realise that this is quite a bit of logic to put in a view, which is why the page takes quite long to load I guess.
playlist.erb
<% loaded_tweets = TweetsController.load_tweets(current_user) %>
<% if loaded_tweets.any? %>
<table class='tweet_view'>
<thead>
<tr class='tweet_row'>
<th class="fixed_cover"><div class='tableheader'><h6 style='color:white'>Cover</h6></div></th>
<th class="fixed_spotify"><div class='tableheader'><h6 style='color:white'>Spotify</h6></div></th>
<th class="fixed_title"><div class='tableheader'><h6 style='color:white'>Track title</h6></div></th>
<th class="fixed_artist"><div class='tableheader'><h6 style='color:white'>Artist</h6></div></th>
<th class="fluid"><div class='tableheader'><h6 style='color:white'>Album</h6></div></th>
</tr>
</thead>
<tbody>
<% loaded_tweets.reverse_each.each do |tweet| %>
<%=new_tweet(tweet.text)%>
<% end %>
</tbody>
</table>
<% else %>
<center>
<p><h8><b>No tweets found!</b></h8></p>
</center>
<% end %>
The _tweet.erb partial just adds a new row for each song.
_tweet.erb
<tr class='tweet_row'>
<td class='tweet_column'>
<div class='tablerow#cover'>
<%= image_tag(#cover,:class => 'album_cover')%>
</div>
</td>
<td class='tweet_column'>
<div class='tablerow#spotify'>
<h5><%= link_to image_tag('spotify', :class => 'spotify_image'), 'https://open.spotify.com/track/'+#spotify %></h5>
</div>
</td>
<td class='tweet_column'>
<div class='tablerow'>
<h5><%=#track_name%></h5>
</div>
</td>
<td class='tweet_column'>
<div class='tablerow'>
<h5><%=#artist%></h5>
</div>
</td>
<td class='tweet_column'>
<div class='tablerow'>
<h5><%=#album%></h5>
</div>
</td>
</tr>
Change playlist.erb to playlist.html.erb
<div id="tweets">
<%= render 'tweet') %>
</div>
....
....
<script>
$( document ).ready(function() {
// call the controller function here
});
</script>
In controller methode add
....
....
respond_to do |format|
format.js
end
create one more file in views folder like action_name.js.erb and add
$('#tweets').html('<%= j(render "tweet") %>')
First of all, I'm experimenting with Ruby on Rails for the first time.
I'm doing a simple exercise of designing a form to receive events information and save those events in Google Calendar.
To save the events on Google Calendar I'm using the following gem: http://googlecalendar.rubyforge.org/
I have the following code for the view.
<h1>Welcome to Ruby On Rails Calendar</h1>
<h3>Add Event</h3>
<form action="/google_calendar/create" method="post">
<table>
<tr>
<td>Title</td><td><input type="text" /></td>
</tr>
<tr>
<td>Begin Date</td><td><input type="date" name="begindate" id="bagindate" /><input type="time" name="beginhour" id="beginhour" /></td>
</tr>
<tr>
<td>End Date</td><td><input type="date" name="enddate" id="enddate" /><input type="time" name="endhour" id="endhour" /></td>
</tr>
<tr>
<td>Local</td><td><input type="text" name="local" id="local" /></td>
</tr>
<tr>
<td>Description</td><td><input type="textarea" rows="10" name="description" id="description" /></td>
</tr>
<tr>
<td><input type="Submit" value="Save" /></td>
</tr>
</table>
</form>
<%= #result_message %>
And for the controller I have this code (mostly taken from the gem site I shared previously).
class GoogleCalendarController < ApplicationController
def create
send_event(params[:title],params[:begindate] + " " + params[:beginhour], params[:enddate] + " " + params[:endhour], params[:local], params[:description])
#result_message = 'Event sent successfully'
render :welcome => index
end
private def send_event(title, begin_datetime, end_datetime, local, description)
require 'googlecalendar'
google_calendar_service = GData.new
google_calendar_service.login(Rails.configuration.google_calendar_email, Rails.configuration.google_calendar_password)
event = { :title => title,
:content => description,
:where => local,
:startTime => begin_datetime,
:endTime => end_datetime}
google_calendar_service.new_event(event)
end
end
The thing is that when I try to save an event I get the following error.
uninitialized constant GoogleCalendarController::GData
Supposedly GData is a class defined in the googlecalendar gem, but seems to not being recognized as such.
I have gem 'googlecalendar' on my Gemfile, did bundle install and it appears when I do bundle show googlecalendar.
Does anyone know what can be causing this?
The documentation is little bit wrong
try this
require 'googlecalendar'
google_calendar_service = Googlecalendar::GData.new
Since you didnot specify the namespace so first Ruby searched it in the ::global namespace and didnot find, so expected it to be GoogleCalendarController::GData
References
Code from the gem's lib/googlecalendar.rb, you can see the namespace is Googlecalendar
$:.unshift(File.dirname(__FILE__)) unless
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
module Googlecalendar
# List of lib files to include
FILES = %w{calendar.rb dsl.rb event.rb gcalendar.rb gdata.rb ical.rb net.rb version.rb}
end
# Add all FILES as require
Googlecalendar::FILES.each { |f| require "googlecalendar/#{f}"}
I have a user control: VendorDDL.ascx, with the following code:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<List<MeetingCalendar.Models.Vendor>>" %>
<table>
<tr>
<th></th>
<th>
VendorId
</th>
<th>
VendorName
</th>
</tr>
<% foreach (var item in Model) { %>
<tr>
<td></td>
<td>
<%= Html.Encode(item.VendorId) %>
</td>
<td>
<%= Html.Encode(item.VendorName) %>
</td>
</tr>
<% } %>
</table>
My view: Create.aspx, has the following code snippet:
<p>
<label for="VendorNameSearch">Vendor Name:</label>
<input type="text" name="VendorNameSearch" id="VendorNameSearch" style="width:100px" />
<input type="submit" value="search" />
</p>
<% Html.RenderPartial("VendorDDL", MeetingCalendar.Controllers.HomeController.VendorsToSelect); %>
And everything works fine when I load up the Create view. The VendorDDL control is populated with the default values that are found in the VendorsToSelect. My controller has a List<Vendor> VendorsToSelect, which is getting updated properly.
Here is the problem: when the user clicks the SEARCH button, this fires off code in the Controller: return PartialView("VendorDDL", VendorsToSelect); I can see that VendorsToSelect is getting populated correctly based upon the user search.
I can step through the code, line-by-line, and see that immediately after return PartialView("VendorDDL", VendorsToSelect);, the debugger goes directly to the VendorDDL.ascx, and I can see that the Model is properly populated with the new VendorsToSelect, and the item.VendorId and item.VendorName are showing the correct values. But when debugging is done, and the Create view is shown, the VendorDDL control is not showing the new data.
Any suggestions?
I think that the output of your controller is discarded because the view (Create) has the same Html.RenderPartial("VendorDDL", MeetingCalendar.Controllers.HomeController.VendorsToSelect) as during initial load.
If I understand your problem correctly (and admittedly, without looking at the controller I may not) - you need to pass the model dynamically. The simplest (but not the most efficient) way would be to have jquery call $.load("/Home/VendorDDL") that would populate with the whole model; and then on submit hijax the form and pass form data to the same controller action.
I'm starting to develop in ASP.NET and I can't find any example of a very simple use-case:
I've got some model objects displayed on a view.
I added a checkbox so that the user can choose the one he/she wants to see.
Then the user clicks on a link and he/she should see the model objects he/she selected displayed in another view.
1) What's the best way to get the selected items list?
At the moment I decorated my model with an IsSelected property because that's what I'd do in a ViewModel but that may not be the right answer.
2) How to pass the selected data to the next controller?
In all the examples that I've seen, data is "hardcoded" in the link and is per-object.
I haven't seen any example of a user-selection in any sample from the ASP MVC site.
EDIT: I'm afraid it wasn't that clear. What I've got is that:
<table style="width: 100%;">
<% foreach (Vehicle vehicle in Model)
{ %>
<tr>
<td>
<% 'Here be bound checkbox' %>
</td>
<td>
<%= Html.ActionLink("Show", "Index", "Map", vehicle.Name, null) %>
</td>
<td >
<%= Html.Encode(vehicle.Name) %>
</td>
<td >
<%= Html.Encode(vehicle.LastPositionReceived) %>
</td>
<td >
<%= Html.Encode(vehicle.Status) %>
</td>
<td >
<%= Html.Encode(vehicle.LocationDescription) %>
</td>
</tr>
<% } %>
</table>
By clicking on the Show link, I can already show a SINGLE item details.
Now I'd like to have the checkbox bound to a property of my model so that I can then trigger an action (with a link or a button) so that only the SELECTED items are sent to the controller.
This is the part that I haven't seen any examples about.
I could add
<% TempData.Add("Vehicles", Model); %>
somewhere and then the vehicles would be passed to the controller but I still need a way to bind the IsSelected property to the model (I don't want to hook up the Checked event and do it manually).
I hope that makes things a bit clearer.
(Thanks for the quick reply BTW ;) )
Honestly, you are not giving much information for us to give a proper answer. But here is a simple example of how you could accomplish what I think you described.
Suppose this is the part in your view where you are listing the selections to the user :
<%foreach (YourModel m in (List<YourModel>)ViewData["ModelsToList"]) {%>
<p>
<input name="selection" type="radio" value="<%=m.ID%>" id="model-<%=m.ID%>" />
<label for="model-<%=m.ID%>"><%=m.Name%></label>
</p>
<%}%>
Then you post that form to a controller action like this :
public ActionResult ShowSelectedModel(int selection) {
YourModel selectedModel = yourModelRepository.getModel(selection);
return View(selectedModel);
}
Then in your ShowSelectedModel view you can display the user's selection.
Was that what you had in mind?
I'm trying to implement something like this:
<div>
<table>
<thead>
<tr>
<td>Port name</td>
<td>Current port version</td>
<td>New port version</td>
<td>Update</td>
</tr>
</thead>
<% foreach (var ip in Ports) { %>
<tr>
<td>
<%= ip.PortName %>
</td>
<td>
<%= ip.CurrentVersion %>
</td>
<td>
<%= ip.NewVersion %>
</td>
<td>
<asp:Button ID="btnUpdate" runat="server" Text="Update" CommandArgument="<% ip.PortName %>" />
</td>
</tr>
<% } %>
</table>
</div>
The button's CommandArgument property is where my code complains about not being able to resolve symbol ip. Is there any way to do what I'm trying to do?
You don't want to use a Webforms button in ASP.NET MVC. MVC is a completely different way of working, and you no longer have the WebForms abstraction.
You have 2 different options you can either replace your asp:Button with an input tag or use a standard hyperlink instead. If you use the input option then you will need to wrap in a form element. The form action should point to a Controller action.
You can't use webform controls in ASP.NET MVC in a trivial manner because they rely on things that are stripped out in MVC. Instead you add a button in two ways, both using the HtmlHelper on the ViewPage:
You can add a button in a form, which is easily handeled in a controller if you have a form for each single button:
<% using(Html.BeginForm("Update", "Ip", new {portName = ip.PortName} )) { %>
....
<input name="action" type="submit" value="Update">
<% } %>
BeginForm() will default to the same controller and action as the view was created from. The other way is to add a link instead, which is more fitting to your example of iterating through a list. For example lets say you have IpController
<%= Html.ActionLink("Update IP", "Update", "Ip",
new {
portName = ip.PortName
})
%>
The link will go to the Update action in IpController with the given portName as parameter. In both cases you'll need this action in IpController:
public ActionResult Update(string portName) {
// ...
}
Hope this helps.
I think you have to enclose your block in Form tags ans runat=server.
FWIW,
I think this text is missing an equals sign:
CommandArgument="<% ip.PortName %>"
Should be
CommandArgument="<%= ip.PortName %>"